Cross-domain super detailed explanation

1. Why do cross-domain problems exist?

Browsers do not allow cross-domain requests because cross-domain requests may cause security risks. Same-Origin Policy is a browser security mechanism that requires scripts executed in web pages to only interact with resources from the same source (same protocol, domain name, and port).
The same-origin policy helps prevent malicious websites from stealing users' sensitive information or conducting other security attacks. If the browser allows cross-domain requests, malicious websites may access sensitive data under other domain names, such as user login credentials, private files, etc., by executing scripts in the user's browser.
Although cross-domain requests are restricted by the same-origin policy, browsers provide some mechanisms to support secure cross-domain communication, such as Cross-Origin Resource Sharing (CORS) and JSONP (JSON with Padding). Through these mechanisms, the server can clearly tell the browser which cross-domain requests are safe and trustworthy, and authorize the browser to access relevant resources.
Despite the limitations of cross-origin requests, the same-origin policy is critical to protecting users and maintaining network security. Developers can solve cross-domain issues by using server-side proxies or by configuring CORS on the server. This ensures that cross-domain requests are only made in a trusted environment and reduces potential security risks.

2. What is cross-domain

When any one of the protocol, domain name, and port of a request URL is different from the current page URL, it is cross-domain.

Current page url Requested page url Is it cross-domain? reason
http://www.test.com/ http://www.test.com/index.html no Same origin (same protocol, domain name, and port number)
http://www.test.com/ https://www.test.com/index.html Cross domain Different protocols (http/https)
http://www.test.com/ http://www.baidu.com/ Cross domain The main domain name is different (test/baidu)
http://www.test.com/ http://blog.test.com/ Cross domain Different subdomain names (www/blog)
http://www.test.com:8080/ http://www.test.com:7001/ Cross domain Different port numbers (8080/7001)

3. How to solve cross-domain issues

3.1 CORS (important)

CORS (Cross-Origin Resource Sharing) is a W3C standard that defines how browsers and servers should communicate when cross-origin resources must be accessed. The basic idea behind CORS is to use custom HTTP headers to allow the browser to communicate with the server to determine whether the request or response should succeed or fail.
CORS requires both browser and server support. Currently, all browsers support this function, and IE browser cannot be lower than IE10.
The entire CORS communication process is automatically completed by the browser and does not require user participation. For developers, there is no difference between CORS communication and AJAX communication from the same source, and the code is exactly the same. Once the browser discovers that the AJAX request is cross-origin, it will automatically add some additional header information, and sometimes an additional request will be made, but the user will not feel it.
Therefore, the key to achieving CORS communication is the server. As long as the server implements the CORS interface, cross-origin communication is possible.
In fact, CORS is easy to understand. The server adds a Header Access-Control-Allow-Origin in the HTTP response: http://www.masikkk.com The header value is the allowed origin. The browser sees its own origin and returns it from the server. If they can be matched, cross-domain is allowed.
Browsers divide CORS requests into two categories: simple requests and not -so-simple requests.

3.1.1 Simple requests and non-simple requests

(1) The request method is one of the following three methods:

  • HEAD
  • GET
  • POST

(2) HTTP header information does not exceed the following fields:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type: limited to three values ​​application/x-www-form-urlencoded, multipart/form-data, text/plain

Any request that does not meet the above two conditions at the same time is a non-simple request.

3.1.2 Cross-domain mainly involves 4 response headers

  • Access-Control-Allow-Origin is used to set the source address that allows cross-domain requests (preflight requests and formal requests will be verified when cross-domain)
  • Access-Control-Allow-Headers Special header information fields allowed to be carried across domains (only verified in preflight requests)
  • Access-Control-Allow-Methods cross-domain allowed request methods or HTTP verbs (only in preflight request verification)
  • Access-Control-Allow-Credentials Whether to allow the use of cookies across domains. If you want to use cookies across domains, you can add this request response header and set the value to true (setting it or not setting it will not affect the request sending, but will only affect the Whether cookies need to be carried across domains, but if set, both preflight requests and formal requests need to be set). However, it is not recommended to use it cross-domain (it has been used in the project, but it is unstable and cannot be carried by some browsers) unless necessary, because there are many alternatives.

3.1.3 Simple request CORS processing process

For simple cross-domain requests, the browser will automatically add the Origin field to the header information of the request, indicating which source the request comes from (protocol + domain name + port). The server should obtain this value and then determine whether to agree to this request. Request and return.

  1. Simple request processing:
    The browser automatically attaches an Origin header to the cross-domain request, which contains the source information of the requested page (protocol, domain name, and port), so that the server can decide whether to respond based on this header information. For example: Origin: http://www.masikkk.com
  2. If the server thinks that the request is acceptable, it adds the header Access-Control-Allow-Origin to the http response, and sets its value to the same source information as the Origin in the request (if it is a public resource, you can set * to indicate that requests from any domain name are accepted. ). For example: Access-Control-Allow-Origin: http://www.masikkk.com
  3. Without this header or with this header but the source information does not match, the browser will reject the request. Note that neither the request nor the response contains cookie information.
  4. If you need to include cookie information, the ajax request needs to set the XMLHttpRequest attribute withCredentials to true, and the server needs to set the response header Access-Control-Allow-Credentials: true

3.1.4 Complex request CORS processing process (OPTION request first)

Non-simple requests are requests that have special requirements for the server, such as the request method is PUT or DELETE, or the type of the Content-Type field is application/json.
CORS requests for complex requests will add an HTTP query request before formal communication, called a preflight request (preflight) . The preflight request uses the http method OPTIONS** to know whether the server allows cross-domain requests. .
3395727666-7909e09b79e67694.png
Complex request processing process:

  1. The browser sends a preflight request

Before sending a real request, the browser first sends a Preflight preflight request to the server. This request uses the OPTIONS method, calls the same API, and sends the following header: Origin must be the same as a simple request, and the value is
request The source information of the page (protocol, domain name and port).
Access-Control-Request-Method is required. The http method used by the request itself, such as PUT.
Access-Control-Request-Headers Optional, custom header information, multiple headers separated by commas.

OPTIONS /cors HTTP/1.1
Origin: https://masikkk.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
  1. Server returns preflight response

After receiving this request, the server can decide whether to allow this type of request. The server communicates with the browser by sending the following headers in the response:
Access-Control-Allow-Origin is required. Same as a simple request. Allows access to the origin. Accepts any domain and returns *
Access-Control-Allow-Methods . Required. Allowed methods, multiple methods separated by commas. Indicates all cross-origin request methods supported by the server. Note that all supported methods are returned, not just the method requested by the browser. This is to avoid multiple "preflight" requests.
Access-Control-Allow-Headers The Access-Control-Allow-Headers field is required if the browser request includes the Access-Control-Request-Headers field. It is also a comma-separated string indicating all header fields supported by the server, not limited to fields requested by the browser in "preflight".
Access-Control-Max-Age is optional and is used to specify the validity period of this preflight request, in seconds. Or how long this Preflight request should be cached.
Preflight request response example:

Access-Control-Allow-Origin: http://devgou.com
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: NCZ
Access-Control-Max-Age: 1728000
  1. Normal requests and responses from the browser

Once the server passes the "preflight" request, every subsequent normal CORS request from the browser will be the same as a simple request, with an Origin header field. The server's response will also have an Access-Control-Allow-Origin header field.

3.1.5 SpringBoot framework implements CORS

1. CorsFilter filter implements global configuration
@Slf4j
@Component
public class CorsFilter implements Filter {
    
    
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    
        HttpServletResponse response = (HttpServletResponse)servletResponse;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, client_id, uuid, Authorization");
        response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        response.setHeader("Pragma", "no-cache");
        filterChain.doFilter(servletRequest,response);
    }
}
2. Rewrite the addCorsMappings method of WebMvcConfigurer to implement global configuration
@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
    
    
        registry.addMapping("/**")//项目中的所有接口都支持跨域
                .allowedOrigins("*")//所有地址都可以访问,也可以配置具体地址
                .allowCredentials(true)
                .allowedMethods("*")//"GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS"
                .maxAge(3600);// 跨域允许时间
    }
}
3. @CrossOrigin annotation local configuration

Directly add methods or classes@CrossOrigin to solve cross-domain problems

/**
 * Created with IDEA
 *
 * @Description xxxx控制层
 * @Version 1.0
 */
@RestController
@CrossOrigin
@RequestMapping("/situation")
public class SituationController extends PublicUtilController {
    
    
 
    @Autowired
    private SituationService situationService;
    // log日志信息
    private static Logger LOGGER = Logger.getLogger(SituationController.class); 
}

3.2 Nginx reverse proxy (important)

Using nginx reverse proxy to achieve cross-domain is the simplest cross-domain method. You only need to modify the configuration of nginx to solve cross-domain problems. It supports all browsers and sessions. There is no need to modify any code and it will not affect server performance.
We only need to configure nginx and configure multiple prefixes on one server to forward http/https requests to multiple real servers. In this way, all URLs on this server have the same domain name, protocol and port. Therefore, for browsers, these URLs are of the same origin and there are no cross-domain restrictions. And in reality, these URLs are actually served by physical servers. The javascript within these servers can call URLs on all these servers across domains.
Specific operation:
Use nginx to forward requests.
Several parameters that need to be configured in nginx:

Access-Control-Allow-Origin:必含,允许的域名,只能填通配符或者单域名
Access-Control-Allow-Methods:必含,允许跨域请求的 http 方法
Access-Control-Allow-Headers:返回支持的 http 请求头
Access-Control-Allow-Credentials:可选,标志着当前请求是否包含 cookies 信息,布尔值。只有一个可选值:true,如果不包含 cookies,请略去该项,而不是填 false。这一项与XmlHttpRequest 对象当中的 withCredentials 属性应保持一致,即 withCredentials 为true时该项也为 true;withCredentials为false时,省略该项不写。反之则导致请求失败。
Access-Control-Max-Age:可选,以秒为单位的缓存时间,用于缓存预检请求。
http {
  ......
  add_header Access-Control-Allow-Origin *;
  add_header Access-Control-Allow-Headers X-Requested-With;
  add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
  ......
}
server {
	listen       80;
	server_name  xxx.com;
 
	location /xxx-web/papi {
		add_header 'Access-Control-Allow-Origin' $http_origin;
		add_header 'Access-Control-Allow-Credentials' 'true';
		add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
		add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
		add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
		if ($request_method = 'OPTIONS') {
			add_header 'Access-Control-Max-Age' 1728000;
			add_header 'Content-Type' 'text/plain; charset=utf-8';
			add_header 'Content-Length' 0;
			return 204;
		}
		root   html;
		index  index.html index.htm;
		proxy_pass http://127.0.0.1:7071;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_connect_timeout 5;
	}
 
	location /xxx-web {
		add_header 'Access-Control-Allow-Origin' $http_origin;
		add_header 'Access-Control-Allow-Credentials' 'true';
		add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
		add_header 'Access-Control-Allow-Headers' 'DNT,web-token,app-token,Authorization,Accept,Origin,Keep-Alive,User-Agent,X-Mx-ReqToken,X-Data-Type,X-Auth-Token,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
		add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
		if ($request_method = 'OPTIONS') {
			add_header 'Access-Control-Max-Age' 1728000;
			add_header 'Content-Type' 'text/plain; charset=utf-8';
			add_header 'Content-Length' 0;
			return 204;
		}
		root   html;
		index  index.html index.htm;
		proxy_pass http://127.0.0.1:8080;
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_connect_timeout 5;
	}
 
	location / {
		root   /var/www/xxx/wechat/webroot;
		index  index.html index.htm;
	}
 
	error_page   500 502 503 504  /50x.html;
	location = /50x.html {
		root   html;
	}
}

The difference between these two configurations lies in the granularity and scope of the cross-domain settings. The first piece of configuration sets global cross-domain configuration in the "http" block, using the wildcard character
"*", which means that requests from all sources are allowed for cross-domain access. It sets
the "Access-Control-Allow-Origin", "Access-Control-Allow-Headers" and
"Access-Control-Allow-Methods"
fields in the response header to specify domain names and request headers that allow cross-domain access and request methods. Such a setting will take effect on all requests throughout the server, including all "location" blocks.
The second piece of configuration sets cross-domain configuration in a specific "location" block. It only takes effect for request paths starting with "/api". This configuration sets
the "Access-Control-Allow-Origin", "Access-Control-Allow-Headers" and
"Access-Control-Allow-Methods"
fields in the response header, and sets more details for the specific request path. Allowed domain names, request headers and request methods. For other request paths, such as the root path "/", these cross-domain configurations will not be applied.
Therefore, the first configuration is a global cross-domain configuration and applies to the entire server, while the second configuration is a cross-domain configuration under a specific path and only applies to the "/api" path.
Generally speaking, if you just need to simply allow cross-domain access for requests from all sources, you can use the first configuration. If you need to set more detailed cross-domain policies for specific interfaces or paths, you can use the second stage of configuration. The configuration method should be selected based on your needs and application scenarios.

If you only respond to simple requests and do not use cookies, just set Access-Control-Allow-Origin as the front-end domain name. For example,
only http://devgou.com is allowed to access, you can configure it as follows:

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

If you need to allow access from any domain, you can configure it like this

add_header Access-Control-Allow-Origin *;

If you don’t want to allow all but need to allow multiple domain names, you need to use the nginx map directive.
For example, you want to allow access to four domain names in the following map:

http {
  map $http_origin $corsHost {
    default 0;
    "~http://madaimeng.com" http://madaimeng.com;
    "~http://devgou.com" http://devgou.com;
    "~http://masikkk.com" http://masikkk.com;
    "~http://localhost:4000" http://localhost:4000;
  }

  server {
    listen       80;
    server_name  api.masikkk.com api.madaimeng.com api.devgou.com;

    location / {
      add_header 'Access-Control-Allow-Origin' $corsHost;
      proxy_pass http://localhost:8001;
    }
  }
}

Summarize:

  • The same-origin policy is a standard that browsers need to follow, but if the server makes a request to the server, it does not need to follow the same-origin policy.
  • CORS supports all types of HTTP requests and is the fundamental solution for cross-domain HTTP requests.
  • In daily work, the most commonly used cross-domain solutions are cors and nginx reverse proxy.
  • In a word, cross-domain, browser restrictions for security require server-side adaptation.

reference:

  1. https://www.jianshu.com/p/cedc8b1cd84c
  2. https://www.qiufeng.blue/frontend/cors.html

Guess you like

Origin blog.csdn.net/hansome_hong/article/details/131577084