1. Same-origin policy

The same origin policy restricts how documents or scripts loaded from one source interact with resources from another.

Definition of a source: Two pages have the same source if the protocol, port (if one is specified) and host are the same for both pages.

The following table shows the relative store.company.com/dir/page.ht… Examples of same-origin detection:

URL The results of why
Store.company.com/dir/inner/a… successful The same domain name
Store.company.com/dir2/other…. successful Different folders under the same domain name
store.company.com/secure.html failure Different protocols (HTTPS)
Store.company.com: 81 / dir/etc. HTM… failure Different ports (81)
News.company.com/dir/other.h… failure Different hosts (News)

2. Cross-domain with the same primary domain

The document.domain scenario applies only to interactions between frameworks in different subdomains, and to different sources whose primary domains must be the same.

Pages may change their own sources, but with some limitations. A script can set the value of document.domain to its current domain or to the superdomain of its current domain. If it is set to the superdomain of its current domain, the shorter domain is used for subsequent raw checks. For example, assume that the document in a script store.company.com/dir/other.h… Execute the following statement:

 document.domain = "company.com";Copy the code

After this statement is executed, the page will successfully pass the call to company.com/dir/page.ht… Homology detection based on. Note: the browser saves the port number separately. Any assignment, including document.domain = document.domain, overwrites the original port number with a null value. Therefore, scripts for company.com:8080 pages cannot communicate with company.com simply by setting document.domain = “company.com”. The assignment must be accompanied by an upper end number to ensure that the port number is not null.

1) in www.a.com/a.html:document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src =  'http://www.script.a.com/b.html';  
ifr.display = none;
document.body.appendChild(ifr);
ifr.onload = function(){ 
    var doc = ifr.contentDocument || ifr.contentWindow.document;                                                          
    ifr.onload = null;
};
2) in www.script.a.com/b.html:document.domain = 'a.com';// Note: When using document.domain to allow secure access to its parent, you need to set the document field to have the same value in the parent and child fields. This is necessary even if doing so simply sets the parent field back to its original value. Otherwise, permissions may be incorrect. It's all a.com.Copy the code

3. Cross-domain of completely different sources (communication between two pages)

(1) Use location.hash to cross domains

Suppose the file cs1.html under the domain name a.com is communicating with the file cs2.html under the domain name jianshu.com. A hidden iframe is automatically created. The SRC of the iframe points to the cs2. HTML page under the jianshu.com domain. 2. Cs2.html responds to the request and then passes the data by modifying the hash value of cs1.html. 3. At the same time, add a timer on cs1.html to determine whether the value of location.hash has changed at regular intervals.

Note: Since the two pages are not in the same domain, IE and Chrome do not allow you to change the value of parent-location. hash, so use a proxy iframe under the a.com domain name.

Advantages: 1. It can solve cross-domain problems with completely different domain names. 2. Two-way communication can be realized. Disadvantages: Location. hash will be directly exposed in the URL, and some browsers will generate history, data security is not high and affect the user experience. In addition, due to the limitation of URL size, support for the transfer of data is not large. Some browsers do not support the onHashchange event and require polling to learn about URL changes.

(2) Use window.name to cross domains

The window object has a name attribute that has the following characteristics: That is, during the life cycle of a window, all pages loaded by the window share a window.name, and each page has read and write permissions to window.name, and window.name is persisted in all pages loaded by a window. The magic of the window.name property is that the name value persists from page to page (and even from domain to domain) and can support a very long name value (2MB).

 window.name = data;// The parent window opens a child window that loads a page from a different source, which writes the information.
 location = 'http://parent.url.com/xxx.html';// Then the child window jumps back to a url in the same domain as the main window.
 var data = document.getElementById('myFrame').contentWindow.name.// The main window can then read the child window's window.name.Copy the code

If the scenario is communicating with an iframe, the SRC of the iframe needs to be set to a page address of the current domain.

(3) Use window.postMessage to cross domains

HTML5 addresses this problem by introducing a new API: Cross-document Messaging. The API adds a window.postMessage method to window objects, allowing cross-window communication regardless of whether the two Windows are identical. PostMessage has the following compatibility:





Paste_Image.png

You can see that Internet Explorer 8+, Chrome, Firefox, Opera and Safari will all support this feature. But Internet Explorer 8 and 9, and Firefox 6.0 and later only support strings as postMessage messages.

var popup = window.open('http://bbb.com'.'title');//The parent window HTTP://Aaa.com To child window HTTP://Bbb.com sends a message and calls the postMessage method. popup.postMessage('Hello World! '.'http://bbb.com');Copy the code

The first argument to the postMessage method is the specific message content, and the second argument is the origin of the window that received the message, i.e. “protocol + domain + port”. You can also set this parameter to *, which indicates that the domain name is not limited and the message is sent to all Windows.

Both parent and child Windows can listen for messages from each other through message events. The event object for the message event provides the following three properties:

1. Event. source: window for sending messages. 2. Event. origin: the url to which the message is sent. 3. Event. data: message content.

var onmessage = function (event) {  
  var data = event.data;/ / message
  var origin = event.origin;// Source address
  var source = event.source;// Source Window object
  if(origin == "http://www.aaa.com") {console.log(data);//hello world!  
  }  
  source.postMessage('Nice to see you! '.The '*');
};  
if (typeof window.addEventListener ! ='undefined') {  
  window.addEventListener('message', onmessage, false);  
} else if (typeof window.attachEvent ! ='undefined') {  
  //ie  
  window.attachEvent('onmessage', onmessage);  
}Copy the code

4. Cross-domain AJAX requests from different sources

(1) Cross domain through JSONP

Rationale: Web pages request JSON data from the server by adding a <script> element, which is not restricted by the same origin policy. The server receives the request and returns the data in a named callback function. Examples are as follows:

function todo(data){
  console.log('The author is: '+ data.name);
}
var script = document.createElement('script');
script.src = 'http://www.jianshu.com/author?callback=todo';// Make a request to the server www.jianshu.com. Note that the query string for this request has a callback parameter that specifies the name of the callback function.
document.body.appendChild(script);
// When the server receives the request, it returns the data as an argument to the callback function.
todo({"name": "fewjq"});
// The script requested by the Copy the code

Advantages: simple application, old browser all support, server transformation is small. No XMLHttpRequest or ActiveX support is required. Disadvantages: Only SUPPORT GET requests.

(2) Cross domain through WebSocket

WebSocket is a communication protocol that prefixes ws:// (unencrypted) and WSS :// (encrypted). This protocol does not enforce the same origin policy and can be used for cross-source communication as long as the server supports it.

(3) Cross-domain through CORS

A cross-origin HTTP request is made when a resource requests a resource from another domain. For example, if A Web application of domain A introduces an image resource of domain B with the <img> tag, the Web application of domain A will cause the browser to make A cross-domain HTTP request. In today’s Web development, using cross-domain HTTP requests to load all kinds of resources, including CSS, images, JavaScript scripts, and other types of resources, has become a common and popular method.

As you know, browsers block the return of cross-domain requests for security reasons. For example, making HTTP requests using XMLHttpRequest objects and Fetch must comply with the same origin policy. Specifically, Web applications can and can only make HTTP requests to resources of the same domain name through the XMLHttpRequest object or Fetch, and not to any other domain name. In order to develop more powerful, richer and more secure Web applications, developers are eager to make Web application technology more powerful and richer without losing security. For example, cross-site HTTP requests can be made using XMLHttpRequest.





Paste_Image.png

The Web Applications Working Group, part of the W3C, has recommended a new mechanism, Cross-Origin Resource Sharing (CORS). This mechanism enables Web application servers to support cross-site access control, making it possible to transfer data securely across sites. It is important to note that this specification is for API containers (such as XMLHttpReques or Fetch) to mitigate the risk of cross-domain HTTP requests.

The Cross-Origin Sharing Standard enables cross-site HTTP requests for the following scenarios:

  • Initiate cross-site HTTP requests using XMLHttpRequest or Fetch.
  • Web fonts (cross-site font resources are used in CSS via @font-face), so sites can publish TrueType font resources and only allow authorized sites to make cross-site calls.
  • WebGL map
  • Draw using drawImage
  • Images/video Images to canvas.
  • Style sheets (using CSSOM)
  • Scripts (for unmuted exceptions)

All browsers support this function. Internet Explorer cannot be earlier than Internet Explorer 10. Initiate with the XMLHttpRequest object. However, Internet Explorer 8 and 9 can implement CORS through the XDomainRequest object. CORS can be divided into simple request, pre-request and request with credential information.

1. Simple requests

(1) Use only GET, HEAD or POST request methods. If POST is used to send data to the server, the content-Type can only be one of Application/X-www-form-urlencoded, multipart/form-data, or Text /plain. (2) Do not use custom headers (such as X-Modified).

An example:

For example, suppose the web application at http://foo.example wants to access the resources at http://bar.other. The following JavaScript generation
// Code should be executed on foo.example:
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/public-data/';
function callOtherDomain() {
  if(invocation) {    
    invocation.open('GET'.url.true); invocation.onreadystatechange = handler; invocation.send(); }}Copy the code




Paste_Image.png

// Let's see what the browser sends to the server and what the server returns to the browser in this scenario:
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/ 5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; Gecko/rv: 1.9.1 b3pre)20081130 
Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml; Q = 0.9, * /*; q=0.8
Accept-Language:en-us,en; q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO- 8859.- 1,utf- 8 -; q=0.7*; q=0.7
Connection: keep-alive
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example // This request comes from http://foo.exmaple.
// The browser sends the request

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.061. 
Access-Control-Allow-Origin: * // This indicates that the server accepts cross-site requests from any site. If the parameter is set to http://foo.example. Other sites will not be able to access http://bar.other's resources across the site.
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
// The server returns the message to the browserCopy the code

As mentioned above, the simplest cross-site request can be made by using Origin and Access-Control-Allow-Origin. However, the server needs to set access-Control-allow-Origin to * or include sites specified by Origin.

2. Pre-request

Unlike the simple request discussed above, a “pre-request” requires that an OPTIONS request be sent to the destination site to determine whether the cross-site request is safe and acceptable for the destination site. This is done because cross-site requests can cause damage to the data at the destination site. A request is treated as a pre-request when: (1) A request is initiated by a method other than GET, HEAD, or POST. Alternatively, use POST, but request data other than Application/X-www-form-urlencoded, multipart/form-data, or Text /plain. For example, use POST to send requests for XML data of type application/ XML or text/ XML. (2) Use custom headers (such as adding headers such as X-Pingother)

An example:

var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}Arun';
function callOtherDomain(){
  if(invocation){
    invocation.open('POST'.url.true);
    invocation.setRequestHeader('X-PINGOTHER'.'pingpong');
    invocation.setRequestHeader('Content-Type'.'application/xml'); invocation.onreadystatechange = handler; invocation.send(body); }}Copy the code

As above, a POST request is created with XMLHttpRequest, a custom request header (X-Pingother: Pingpong) is added to the request, and the data type is specified as Application/XML. Therefore, the request is a cross-site request in the form of a “pre-request”. The browser sends a “pre-request” using an OPTIONS. Based on the request parameters, Firefox 3.1 decides that it needs to send a “pre-request” to see if the server accepts the actual subsequent request. OPTIONS are HTTP/1.1 methods used to obtain more information on the server side, which should not affect server data. Along with the OPTIONS request, the following two request headers are sent:

Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHERCopy the code

Assume that the server successfully responds with the following information:

Access- Control-allow-origin: http://foo.example // Indicates that the server allows the request from http://foo.exampleAccess- control-allow-methods: POST, GET, OPTIONS // Indicates that the server can accept POST, GET, and OPTIONS requestsAccess-Control-allow-headers: x-pingother // Passes a list of acceptable custom request Headers. The server also needs to set one corresponding to the browser. Otherwise, Request Header field X-Requested- will be reportedWith is not allowed by Access-Control-Allow-Headers inError preflight ResponseAccess-Control-Max-Age: 1728000// Tells the browser how long the result of this "pre-request" will be valid. In the example above,1728000SEC represents20Within days, the browser does not need to send a "pre-request" when processing cross-site requests to the server and only needs to judge and process them based on the result.Copy the code

3. Request for attached voucher information

The most interesting feature of XMLHttpRequest and access control is the ability to send credential requests (HTTP Cookies and authentication information). Generally, browsers do not send credential information for cross-site requests. However, if a special flag bit of XMLHttpRequest is set to true, the browser will allow the request to be sent.

An example:

// The script at the http://foo.example site sends a GET request to the http://bar.other site and sets a cookie value. The script code is as follows:
var invocation = new XMLHttpRequest();
var url = 'http://bar.other/resources/credentialed-content/';
function callOtherDomain(){
  if(invocation) {
    invocation.open('GET'.url.true);
    invocation.withCredentials = true; invocation.onreadystatechange = handler; invocation.send(); }}Copy the code

As shown above, line 7 sets the withCredentials flag of XMLHttpRequest to true so that Cookies can be sent along with the request. Because this is a simple GET request, the browser does not send a “pre-request.” However, if the response on the server side does not return the access-Control-allow-Credentials: true header, the browser will not pass the response to the requesting script to keep the information secure.

Assume that the server successfully responds with the following information:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Credentials: true
Set-Cookie: pageAccess=3; expires=Wed, 31-Dec- 2008. 01:34:53 GMTCopy the code

If the bar.other response header does not contain access-Control-allow-credentials: true, the response is ignored. Note: When sending a response to a request with withCredentials, the server must specify the domain name to allow the request. Do not use *. In the example above, if the response header is access-Control-allow-Origin: *, the response will fail. In this example, because the access-Control-allow-origin value is foo.example, the requested domain name, the client returns the content with the credential information. Also note that more cookie information is created as well.

Advantages of CORS: CORS supports all types of HTTP requests and is the fundamental solution for cross-domain HTTP requests.