Talk about some understanding of cross-domain (cross-origin)

1. Related concepts

1. What is cross domain?

Cross-domain, also known as cross-origin, refers to the violation of the same-origin policy of the browser, that is, when the protocol, domain name and port number are not completely consistent. As long as there is one difference between the client and the browser, they belong to different sources, and cross-domain will occur.
Many junior developers have a wrong perception: only ajaxrequests can generate cross-domain. But in fact, this is a very one-sided idea, because the same-origin policy of the browser not only restricts ajaxthe request, but also restricts pictures, fonts, css, audio and video files, iframe and many other Internet resources, but only after each restriction Behavior is different.

2. What is cross-site?

Similar to cross-domain, there is also a concept of cross-site. Cross-site only refers to the situation of different domain names (including top-level domain names and second-level domain names), so it is actually an inclusive relationship with cross-domain: cross-site must cross-domain Domain, but cross-domain does not necessarily mean cross-site.
For example: sending an ajax request from f1.a.com to f2.a.com constitutes cross-domain, but not cross-site, because the domain names of the two are the same; and sending from f1.a.com to f1.b.com The request constitutes cross-site and cross-domain, because the second-level domain names of the two are different.

3. What is a domain name?

A domain name is the name of a computer on the Internet. It consists of a series of .connected character strings and is used to identify the electronic location of the corresponding computer during data transmission. Moreover, a domain name is actually a synonym for an IP address. When we use a domain name to access a website, the Internet will use DNS to find the corresponding IP address, and then we can access the corresponding computer.
The domain name itself has a set of very complicated naming rules, so we won’t go into details here. Its format is roughly as follows. Let’s take it as an example for a [三级域名].二级域名.顶级域名simple www.three.two.comunderstanding. Among them .comare top-level domain names, .twosecond-level domain names, .threeand third-level domain names, and wwwis the hostname.

2. Relevant understanding

1. The significance of cross-domain existence

We have talked about so many cross-domain solutions, but we have to think about such a question: why does the browser set up such a barrier? Almost everyone knows the answer, and that is for safety. But who is this security for?
Some people say that it is for the safety of the browser, to avoid the execution of malicious scripts and cause damage to the client, but this is one-sided.
Some people also say that it is for the security of the server to avoid the server being attacked, but it can be found through packet capture that when there is a cross-domain, the data on the server has been completely returned, that is to say, the server does not know about the cross-domain, so this This statement is also one-sided.
In fact, the real meaning of cross-domain is to protect the security of data resources , such as: pictures, fonts, audio and video, css, js, etc. That is to say: we can determine which applications our private resources are open to and which resources are prohibited from accessing through cross-domain.
Take an example in life: resources are items on supermarket shelves, and any user can enter the supermarket without being blocked. But when you go out, if you don't pay, the goods will be blocked. At this time, the cashier is equivalent to the role of the browser, verifying the product and the user. Only after the user has paid and has permission, can the user leave with the product, otherwise the person leaves and the product stays, which means cross-domain up.

2. Several cross-domain solutions

Please refer to my blog: Same Origin Policy and Cross-Domain Solutions

3. When requesting across domains, how can relevant credentials be carried?

When ajaxa cross-domain request occurs, even if the cross-domain is solved by one of the above methods, the request will not carry relevant credentials by default (such as cookies, SSL certificates, HTTP authentication information, etc.). But in some scenarios we need these credentials.
To solve this problem, we need the cooperation between the client and the server. The client needs to be set xhr.withCredentialsto true, if it is cross-domain, it will carry all cookies, if it is cross-site, it will only carry cookies with attributes samesite=noneset ( SecureAt the same time, it must be the https protocol, otherwise it will not take effect).


xhr.withCredentials = true;

Set-Cookie: ***** SameSite=None; Secure

In addition to the settings at the code level, the client also needs to check the browser settings. If the browser has set the "Organize third-party cookies" option, then it cannot carry any cookies when cross-domain (Safari in any mode and Chrome's incognito mode) Checked by default, unchecked in Chrome normal mode)
insert image description here

The server needs to set the response header Access-Control-Allow-Credentialsastrue

// 以nginx为例
add_header Access-Control-Allow-Credentials true;

4. Simple request to generate a specific cross-domain solution

First of all, we need to clarify a concept: what is a simple request?
When a request meets the following five conditions at the same time, it is a simple request:

  • ① The request method is one of get/head/postthe three .
  • ② In addition to user-agentthe automatically set headers, only one of the cors-safe headers (request headers) can be used: accept, accept-language, content-language, content-type.
  • ③It content-typecan only be: text/plain, multipart/form-data, application/x-www-form-urlencodedone of them.
  • ④ None XMLHttpRequest of the object has any event listeners registered; XMLHttpRequestthe object can be accessed using XMLHttpRequest.uploadthe property .
  • ReadableStreamThe object .

Normally, conditions ④ and ⑤ will not appear, so we only need to focus on the first three.
When a simple request generates a cross-domain, we only need to set the response header on the server: Access-Control-Allow-Origin: *(或者具体的origin地址)to solve the cross-domain problem.
However, when the client sets the request xhr.withCredentials = true, the request will carry credentials, so Access-Control-Allow-Originthe value cannot be set to *, and must be a specific origin address.

//这里可以是变量,也可以是具体写固定的origin
add_header Access-Control-Allow-Origin $http_origin;

5. Specific solutions for solving complex requests across domains

Know the definition of a simple request, so as long as it is not a simple request, it must be a complex request. Several common situations:

  • ① The request method is PUT, DELETEetc except HEAD, GET, POSTother methods.
  • Content-Type② The value in the request header is application/json.
  • ③ There are custom headers in the request header, such as the "Auth" field that we often use for authentication, which is often placed in the request header.

When a complex request is in progress, it is divided into two steps: the first step is that the client sends: optionsa request (preflight request, HTTP/1.1), which will carry the following request header information:

// 告诉服务器,接下来将使用什么请求方法
Access-Control-Request-Method 
// 告诉服务器接下来将携带哪些请求头部(除了user-agent预设的头部之外,通常是自定义头部)
Access-Control-Request-Headers 

After receiving the preflight request, the server will verify it and return the following response header information:

// 告诉客户端允许的请求方法
Access-Control-Allow-Method  
// 告诉客户端允许携带的头部(如果有自定义头部,需要在这里列出)
Access-Control-Allow-Headers 
// 预检请求的响应结果(Access-Control-Allow-Method和Access-Control-Allow-Headers)的缓存时间,不能超过浏览器的默认上限(当前版本Chrome为2小时,firfox24小时)。-1为禁用缓存。
Access-Control-Allow-Max-Age 
// 告知哪些头部可以供客户端通过xhr.getResponseHeader获取到,逗号分隔。即使不设置,也不影响跨域请求的完成
Access-Control-Expose-Headers
 // 告诉客户端允许的origin,对于复杂请求,不能为通配符*,只能为具体的origin 
Access-Control-Allow-Origin 
/ 告诉客户端是否允许携带凭据(cookie)
Access-Control-Allow-Credentials 

The above response header information does not have to be returned in full. We can decide which header information to return according to the specific situation:

  • ① Only Access-Control-Allow-Originthose who must return.
  • ② If there is no special request header, it may not be returned Access-Control-Allow-Headers.
  • ③ If you do not bring the proof, you do not have to return it Access-Control-Allow-Credentials.

In particular, when the client request carries credentials ( withCredentials=true), the values ​​of the following three response headers cannot be set as wildcards *:

//当XHR请求设置了withCredentials=true,以下头部的值不能为*,需要设置具体的值
// 必须为具体的origin,不然会报错提示不能为*
Access-Control-Allow-Origin 
// 必须为具体的header名称,逗号分隔。不会报错提示不能为*,但是不生效
Access-Control-Expose-Headers
// 除了GET、POST、HEAD之外的METHOD名称,逗号分隔。不会报错提示不能为*,但是不生效
Access-Control-Allow-Method

3. The specific performance of several resources after cross-domain generation

1. Cross-domain fonts

When a.comtrying to load a b.comfont under:

// a.com
@font-face {
    
    
  font-family: 'my-font';
  src: url(http://b.com/Alibaba-PuHuiTi-Regular.ttf);
}

The browser console will throw the following cross-domain error: At this time, we only need to set the response header
insert image description here
insert image description here
on the server where the font is located , and authorize it, so that it can be accessed normally:b.coma.com

add_header Access-Control-Allow-Origin 'http://a.com/';

2. Cross-domain pictures

The viewing of pictures will not generate cross-domain, and the main limitation of cross-domain is the download of pictures.
When the pictures are of the same origin, we can download them by acombining attributes with tags :download

<a href="//a.xkw.com/1.jpg" download="1.jpg">下载图片</a>

When the picture is from a different source, the above method can only open the picture, but not download it. At this point we can combine canvasdrawing downloads:

//a.com页面
const canvas = document.createElement('canvas')
// 设置画布宽高
canvas.width = '1684'
canvas.height = '1190'
const cxt = canvas.getContext("2d");
const img = new Image();
img.crossOrigin = 'anonymous';
// 图片加载完成后
img.onload = function () {
    
    
  // 将图片渲染到画布上 
  cxt.drawImage(img, 0, 0);
  // 将画布转化成base64
  const image = canvas.toDataURL("image/png")
  // 模拟a标签点击下载
  const dlLink = document.createElement('a');
  dlLink.download = 'testfile';
  dlLink.href = image;
  document.body.appendChild(dlLink);
  dlLink.click();
  document.body.removeChild(dlLink);
};
// 设置图片地址
img.src = '//b.com/1.jpg';

The most important line of code is to request this image in the form of , and the response header that the server needs to set: img.crossOrigin = 'anonymous', if the client does not set it, an error will be reported: meaning that the polluted canvas cannot be exported as base64 Encoding format, because a cross-domain picture is drawn above. Similarly, if the server does not set the corresponding response header, it is still cross-domain, and an error will be reported.CORSCORSAccess-Control-Allow-Origin: https://a.comimg.crossOrigin = 'anonymous'
insert image description here

3. Cross-domain JavaScript files

Although the execution of JavaScript is not subject to cross-domain restrictions, if the host page wants to catch the exception thrown in the imported js file, it needs to be configured at this time, that is, to add attributes to CORSthe label <scriot>:crossorigin="anonymous"

<script src="//b.com/b.js" crossorigin="anonymous"></script>

The corresponding js file must also return the corresponding CORSresponse header:

Access-Control-Allow-Origin: http://a.com或者*

After the configuration is complete, the host page can obtain complete exception information through the following code:

window.onerror = function (msg, url, line) {
    
    
  console.log(msg, url, line);
}

Guess you like

Origin blog.csdn.net/weixin_45092437/article/details/127838409