The same-origin policy
The same origin policy was introduced to browsers by Netscape in 1995. Currently, all browsers implement this policy.
Originally, it meant that the Cookie set by page A could not be opened on page B unless the two pages were “homologous”. By homology we mean “three of the same” :
- The agreement is the same
- Domain name is the same
- The same port
The purpose of the same origin policy is to ensure the security of user information and prevent malicious websites from stealing data.
Imagine A situation like this: website A is A bank. After the user logs in, website A sets A Cookie on the user’s machine, which contains some privacy information (such as the total amount of deposit). After users leave website A, they visit website B. If there is no same-origin restriction, website B can read the Cookie of website A, and the privacy information will be leaked. What’s more, cookies are often used to save the user’s login status. If the user does not log out, other websites can pretend to be the user and do whatever they want. Because browsers also specify that submitting forms is not subject to the same origin policy.
Therefore, the same origin policy is necessary, otherwise cookies can be shared and the Internet is not safe at all.
With the development of the Internet, the same origin policy has become more and more strict. Currently, there are three behaviors that are restricted if they are not homologous.
- Cookies, localStorage, and indexedDB of non-homogeneous web pages cannot be obtained.
- DOM (IFrame) of non-cognate web pages cannot be accessed.
- You cannot send AJAX requests or FETCH requests to non-same-origin addresses (you can send, but the browser refuses to accept the response).
Ajax cross-domain
The browser’s same-origin policy can lead to cross-domain, meaning that if a protocol, domain name, or port is different, it is treated as a different domain and cannot use Ajax to send HTTP requests to servers from different sources. First we need to clarify a question, the request is cross-domain, the request is sent? The answer is yes, but the browser blocks the response.
Why cross domains
Ajax’s same-origin policy is mainly used to prevent CSRF (cross-site request forgery) attacks. Without Ajax’s same-origin policy, it is very dangerous. Every HTTP request we initiate will carry the cookie corresponding to the request address, so we can do the following attacks:
- The user logs in to his bank page, MyBank.com, which adds the user id to the user’s cookie.
- The user visited the malicious page evil.com. The malicious AJAX request code in the page is executed.
- Evil.com makes an AJAX HTTP request to http://mybank.com, which by default sends the cookie corresponding to http://mybank.com at the same time.
- The bank page extracts the user id from the cookie sent, verifies that the user is correct, and returns the request data in response. That’s when the data gets leaked.
- And because Ajax is executed in the background, the user is unaware of the process.
DOM same-origin policy is the same. If iframes can be accessed across domains, they can be attacked as follows:
- Create a fake website with iframe nested inside a bank’s website, mybank.com.
- Adjust the width and height of the iframe to the entire page, so that users come in just like the bank’s website, except for the domain name.
- At this time, if the user input the account password, our main website can cross-domain access to the DOM node of http://mybank.com, you can get the user’s input, then complete an attack.
So with the cross-domain restriction, we can access the Internet more safely.
Cross-domain solutions
CORS
CORS is a W3C standard, cross-Origin Resource Sharing, that allows browsers to issue XMLHttpRequest requests across source servers.
The entire CORS communication process is completed automatically by the browser without user participation. For developers, CORS communication is no different than normal AJAX communication, with the code exactly the same. As soon as the browser discovers that an AJAX request crosses domains, it automatically adds additional headers, and sometimes an additional request, but the user is unaware of it. Therefore, the key to CORS communication is the server. As long as the server implements the CORS interface, it can communicate across domains.
Server configuration
Common CORS configuration items are as follows:
-
Access-control-allow-origin (Mandatory) – Specifies the allowed domain name. The value can only be * (wildcard) or a single domain name.
-
Access-control-allow-methods (required) – This allows HTTP Methods (commonly POST, GET, OPTIONS) for cross-domain requests.
-
Access-control-allow-headers (must be included if a pre-request contains access-Control-request-headers) – This is a Request for access-Control-request-headers The response, as above, is a comma-separated list that returns all supported headers.
-
Access-control-allow-credentials (Optional) – Indicates whether cookies are allowed to be sent. There is only one optional value: true (must be lowercase). If cookies are not included, omit this item instead of filling in false. This should be consistent with the withCredentials property in the XmlHttpRequest object, that is, it is true when withCredentials is true; When the withCredentials are false, this item is omitted. Otherwise, the request fails.
-
Access-control-max-age (Optional) – Cache time in seconds. The browser does not have to make another precheck request for the same request during the valid time.
CORS decision process across domains
-
The browser first matches the front-end and background IP addresses based on the same origin policy. If the IP addresses are the same origin, the browser directly sends a data request. If the source is different, a cross-domain request is sent.
-
After receiving the cross-domain request from the browser, the server returns the corresponding file header based on its own configuration. If no cross-domain permission has been configured, the file header does not contain the access-Control-allow-origin field. If the domain name has been configured, the access-Control-allow-origin + domain name in the corresponding configuration rule is displayed.
-
The browser matches the access-Control-Allow-Origin field in the received response header. If the field is not present, cross-domain is not allowed and an error is thrown. If the field exists, the system compares the field content with the current domain name. If the field is of the same origin, the system can cross domains, and the browser accepts the response. If the source is different, the domain name is not cross-domain and the browser does not accept the response and throws an error.
The console output is different for the two types of errors mentioned above:
- The server allows cross-domain requests, but Origin specifies a source that is not covered by the license, and the server will return a normal HTTP response. The browser found that the response header was not included
Access-Control-Allow-Origin
Field, knowing that something is wrong, throws an error that is caught by XMLHttpRequest’s onError callback. Note that this error cannot be identified by the status code, because the status code for the HTTP response might be 200.
<! XMLHttpRequest cannot load HTTP://localhost/city.json.
The 'Access-Control-Allow-Origin' header has a value 'http://segmentfault.com' that is not equal to the supplied origin.
Origin 'http://www.zhihu.com' is therefore notallowed access.
Copy the code
- The server does not allow any cross-domain requests
<! XMLHttpRequest cannot load HTTP://localhost/city.json.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://www.zhihu.com' is therefore not allowed access.
Copy the code
A simple request
In fact, browsers classify CORS requests into two categories: Simple request and not-so-simple Request.
A simple request is one that meets the following conditions (generally, only the first two conditions are considered) :
- use
GET, POST, HEAD
One of the request methods. - HTTP headers do not exceed the following fields:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-type: is limited to three values
Application/X-www-form-urlencoded, multipart/form-data, text/plain
- None of the XMLHttpRequestUpload objects in the request have any event listeners registered;
- The XMLHttpRequestUpload object can be accessed using the xmlHttprequest.upload attribute. No ReadableStream object is used in the request.
For simple requests, the browser directly initiates a CORS request. Specifically, the server will decide whether to approve the request according to the Origin field (including protocol, domain name and port) in the request header.
If origin specifies a licensed source, the server will return a response containing several header fields:
Access-Control-Allow-Origin: http://xxx.xxx.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
Copy the code
Non-simple request
Non-simple requests refer to those requests that have special requirements on the server, for example, the request method is PUT or DELETE, or the content-Type is Application/JSON. In fact, anything other than a simple request is a non-simple request.
CORS requests that are not simple requests will issue a preflight request to the server using the OPTIONS method before formal communication. The browser will first ask the server whether the domain name of the current web page is on the server’s license list, and which HTTP verb and header fields can be used. The browser issues a formal XMLHttpRequest request only if it receives a positive response; otherwise, an error is reported.
Here is the header of a precheck request:
OPTIONS /corsHTTP / 1.1Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla / 5.0...Copy the code
Once the server passes the “precheck” request, every subsequent normal BROWSER CORS request is treated as a simple request.
For more information on why simple and non-simple requests are required, please refer to the answer in Zhihu. Why are cross-domain POST requests differentiated into simple and non-simple requests and Content-Type related?
JSONP
The principle of JSONP is to use the SRC attribute of the
// Define the callback method to get the data
function getData(data) {
console.log(data);
}
// Create a script tag and tell the back end that the callback function is called getData
var body = document.getElementsByTagName('body') [0];
var script = document.gerElement('script');
script.type = 'text/javasctipt';
script.src = 'demo.js? callback=getData';
body.appendChild(script);
// Remove the script from the page after it is loaded, otherwise many script tags are generated per click
script.onload = function () {
document.body.removeChild(script);
}
Copy the code
JSONP is simple to use and compatible, but is limited to GET requests.
Server agent
Browsers have cross-domain restrictions, but servers do not have cross-domain problems, so the server can request resources from the domain to be returned to the client.
Typically, we use webpack-dev-server to open a service locally for proxy access when developing in a local environment.
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 both pages and create an iframe in a.test.com to control the window of the iframe.
postMessage
Window. postMessage is an HTML5 API that allows cross-domain messaging between two Windows.
This approach is often used to retrieve third-party page data embedded in a page. One page sends the message, and the other determines the source and receives the message
// Send the message
var receiver = document.getElementById('receiver').contentWindow;
var btn = document.getElementById('send');
btn.addEventListener('click'.function (e) {
e.preventDefault();
var val = document.getElementById('text').value;
receiver.postMessage("Hello "+val+"!"."http://res.42du.cn");
});
// Receive the message
window.addEventListener("message", receiveMessage, false);
function receiveMessage(event){
if(event.origin ! = ="http://www.42du.cn")
return;
}
Copy the code
Details refer to MDN | window. PostMessage
There are also methods like window.name and location.hash. Both are suitable for iframes across domains, but iframes are used less often, so these methods are somewhat outdated.
The resources
Cross-domain resource sharing (CORS
All that cross-domain stuff
MDN | HTTP access control (CORS)