1. What is cross-domain?

If a protocol, subdomain name, main domain name, or port number is different, the protocol is counted as different domains. When domains request resources each other, the protocol is counted as cross-domain.

It is important to note that cross-domain does not mean that the request cannot be sent out. The request can be sent out, and the server can receive the request and return the result normally, but the result is blocked by the browser. Cross-domain communication is restricted by the same origin policy. Only when the sources are the same, the communication can be normal, that is, the protocol, domain name, and port number are the same.

So what are the security reasons for introducing this mechanism?

In fact, it is mainly used to prevent CSRF attacks. To put it simply, a CSRF attack uses a user’s login status to initiate a malicious request.

That is, without the same origin policy, site A can be accessed by Ajax from any other source. If you are currently logged in on site A, then the other party can get any information about you through Ajax. Of course, cross-domain does not completely prevent CSRF.

Then let’s consider the question, the request is cross-domain, so is the request sent at all? The request must have been sent, but the browser intercepted the response. You may be wondering why Ajax can’t make cross-domain requests when you can make them through forms. Because ultimately, cross-domain is about preventing the user from reading content under another domain name, Ajax can get a response that the browser considers unsafe, so it blocks the response. But the form doesn’t get new content, so it can make a cross-domain request. It also shows that cross-domain does not prevent CSRF completely, because the request is made after all.

2. How to cross domains

Common cross-domain methods include JSONP, CORS, PostMessage, etc.

(1) JSONP

JSONP, short for JSON with padding, is a new way to apply JSON. JSONP looks just like JSON, except that the JSON is included in the function call, like this: callback({name: ‘nany’}).

JSONP cross-domain principle

This js file will execute the function specified in the URL parameter and will pass in the JSON data we need as parameter. Jsonp is required to cooperate with the server side.

Front end:

<script>
    function getPrice(data){
    console.log(data);
    }
</script>
<script 
    type="text/javascript" 
    src="http://sdffw.b2b.com/getSupplyPrice?callback=getPrice&bcid=47296567">
</script>
Copy the code

The backend:

const url = require('url');
require('http').createServer((req, res) => {
    const data = {};
    const callback = url.parse(req.url, true).query.callback ;   
    res.writeHead(200)
    res.end(`${callback}(${JSON.stringify(data)}Callback(data) is returned as a string. The front-end page will execute the jsonpCallback(data) function as js. * }).listen(3000,'127.0.0.1');
Copy the code

Callback is a query parameter agreed on the front and back sides. The server side returns an executable JS file, which calls the parameter value of callback, namely getPrice, and returns the corresponding data. We can process the returned data in getPrice method, and finally return the following result:

getPrice({
    "data": {"priceType":"0"."unit":"Jin"},
    "message":"Price get success!!"."state":"1"
})
Copy the code

In the development process, you may encounter multiple JSONP requests with the same callback function name. In this case, you need to package a JSONP function. Here is a simple implementation:

function jsonp(url, jsonpCallback, success) {
  let script = document.createElement('script')
  script.src = url
  script.async = true
  script.type = 'text/javascript'
  window[jsonpCallback] = function(data) {
    success && success(data)
  }
  document.body.appendChild(script)
}
jsonp('http://xxx'.'callback'.function(value) {
  console.log(value)
})
Copy the code

JSONP cross-domain is not affected by the same origin policy as the following CORS cross-domain and has better compatibility. However, JSONP cross-domain also has its disadvantages, which are mainly reflected in:

  • It supportsGETRequested but not supportedPOSTAnd so onHTTPThe request.
  • It only supports cross-domainHTTPRequesting this case does not resolve two pages or in different domainsiframeThe problem of data communication between.
  • JSONPLoading code execution from another domain, if the domain is insecure and carries some malicious code with it, there is a security risk to determineJSONPIt is not easy to fail a request

(2) CORS

CORS requires both browser and backend support. Internet Explorer 8 and 9 need to be implemented through XDomainRequest.

The browser will automatically carry out CORS communication, the key to achieve CORS communication is the back end. As long as the backend implements CORS, cross-domain is achieved. To enable CORS, set access-Control-allow-Origin on the server. This attribute indicates which domain names can access resources. If a wildcard is set, all websites can access resources.

Although setting up CORS has nothing to do with the front end, solving cross-domain problems in this way can result in two cases of simple and complex requests being sent.

A simple request

In the case of Ajax, a simple request is triggered when the following conditions are met

Use one of the following methods:

The GET HEAD POST content-type value is limited to one of the following: Any XMLHttpRequestUpload object in the Text /plain Multipart /form-data Application/X-www-form-urlencoded request does not register any event listeners; The XMLHttpRequestUpload object can be accessed using the xmlHttprequest.upload attribute.Copy the code

Complex request

Obviously, a request that does not meet these criteria is a complex request.

For complex requests, a precheck request, which is the Option method, is first made to know whether the server allows cross-domain requests. For precheck requests, if you have used Node to set up CORS, you may have encountered a pit like this.

The following uses the Express framework as an example:

app.use((req, res, next) => {
    res.header('Access-Control-Allow-Origin'.The '*')
    res.header('Access-Control-Allow-Methods'.'PUT, GET, POST, DELETE, OPTIONS')
    res.header(
        'Access-Control-Allow-Headers'.'Origin, X-Requested-With, Content-Type, Accept, Authorization, Access-Control-Allow-Credentials'
    )
    next()
})
Copy the code

The request validates your Authorization field, otherwise an error is reported.

After the current end initiates a complex request, you will find that even if your code is correct, the result will always return an error. Because the precheck request also goes into the callback, the next() method is also triggered, and because the precheck request does not contain the Authorization field, the server reports an error.

The solution to this problem is as simple as filtering the Option method in the callback.

res.statusCode = 204
res.setHeader('Content-Length'.'0')
res.end()
Copy the code

Advantages and disadvantages of CORS:

  • Easy to use, more safe
  • supportPOSTRequest mode,
  • CORSIs a new cross-domain problem solution, compatibility problems exist, only supportedIE 10The above

(3) Reduced domain (document.domain)

This mode can be used only when the secondary domain names are the same. For example, a.test.com and b.test.com are used in this mode.

Just add document.domain = ‘test.com’ to the page to indicate that the secondary domain is the same. Modifying document.domain only applies to interactions between frameworks in different subdomains.

(4) postMessage

The window.postMessage(message,targetOrigin) method is a new feature introduced in HTML5. It can be used to send messages to other window objects, regardless of whether the window object belongs to the same or different source. Browsers such as Internet Explorer 8+, FireFox, Chrome, and Opera already support window.postMessage.

The window object from which the postMessage method is called is the window object from which the message is to be received. The first argument to this method, Message, is the message to be sent, and can only be a string. The second parameter, targetOrigin, is used to restrict the field of the window object that receives the message. If you do not want to restrict the field, you can use the wildcard *.

The Window object that needs to receive the message gets the incoming message by listening for its own Message event, the content of which is stored in the event object’s Data property.

/ / messaging client window. The parent. PostMessage ('message'.'http://test.com'Var MC = new MessageChannel() Mc.addeventlistener ()'message', event => {
var origin = event.origin || event.originalEvent.origin
    if (origin === 'http://test.com') {
    	console.log('Verified')}})Copy the code

(5) window.name

The name attribute of the window has a characteristic:

During the life cycle of a window, all pages loaded by the window share the same window.name, and each page has read and write permissions to window.name. Window. name is persisted in all pages loaded by a window and will not be reset for new pages.

(6) Web Sockets

Web Sockets Principle:

After the JS Web socket is created, an HTTP request is sent to the browser to initiate the connection. After the server responds, the established connection is switched from HTTP to Web SOCKT using an HTTP upgrade.

Refresh your brain:

CSRF attack mechanism

Cross Site Request Forgery (CSRF). We know that XSS is a cross-site scripting attack, which is to execute the attacker’s script in the user’s browser to obtain information such as cookies. CSRF, however, borrows the user’s identity and sends a request to the Web server, which is called “cross-site request forgery” because the request is not intended by the user.

The general attack process of CSRF is that the attacker injects a malicious CSRF attack URL (cross-site URL) into the target website. When the user (login) visits a specific webpage, if the user clicks on the URL, the attack will be triggered. In the webpage corresponding to the malicious URL, Use to make a GET request to the target site, which carries cookie information and thus borrows the identity of the user. This request can be any request that the user on the target site has permission to access. You can also use javascript to construct a POST request to submit a form. Such as constructing a post request to transfer money.

Therefore, the attack of CSRF is divided into two steps. First, the malicious URL address is injected, and then the attack code is written in the address, and the same tag is used or Javascript script is used

CSRF defense

referer

Because bogus requests are generally initiated from third-party sites, the first defense is to determine the referer header and determine a CSRF attack if the request is not from the site itself. However, this method can only defend against cross-site CSRF attacks, not against same-site CSRF attacks (although same-site CSRF attacks are more difficult).

Use captcha

Use a captcha for every important post submission page, because third party sites can’t get a captcha. And the use of mobile verification codes, such as mobile verification codes used to transfer money.

Using a token

Each web page contains a token generated by the Web server. When submitting the token, the server also submits the token to the server. If the token is incorrect, the server determines the CSRF attack.

Change the sensitive get operation to POST, and then use the token in the form. Using POST as much as possible also helps defend against CSRF attacks.

Please note that the whole article is for study notes, multi-reference summary, if there is any copyright conflict, please leave a message, after receiving the message will indicate the copyright source.