Web - what is cross domain? Why? How to solve it?

Posted by chings on Mon, 03 Jan 2022 19:06:29 +0100

1, Homology strategy

1. Introduction

Homology policy, which is a famous security policy proposed by Netscape.
When the two tab pages of a browser open the pages of Baidu and Google respectively
When the baidu tab page of the browser executes a script, it will check which page the script belongs to,
That is, check whether it is homologous. Only scripts homologous to Baidu will be executed. If it is not from the same source, when requesting data, the browser will report an exception in the console to prompt that access is denied.
The same origin policy is the behavior of the browser to protect the local data from being polluted by the data obtained by JavaScript code. Therefore, what is intercepted is the data reception of the request sent by the client, that is, the request is sent, the server responds, but it cannot be received by the browser.

2. Examples

The so-called homology means that the domain name, protocol and port are the same.
The following table shows the and URLs http://store.company.com/dir/page.html An example of comparing the source of:

URLresultreason
http://store.company.com/dir2/other.htmlHomologyOnly the paths are different
http://store.company.com/dir/inner/another.htmlHomologyOnly the paths are different
https://store.company.com/secure.htmlfailDifferent agreement
http://store.company.com:81/dir/etc.htmlfailDifferent ports (http: / / the default port is 80)
http://news.company.com/dir/other.htmlfailDifferent hosts

3. Role

The original "homology policy" mainly restricted the access of cookies. The cookies set by web page A could not be accessed by web page B unless web page B and web page A were "homologous"—— Prevent website cookies from being obtained by other pages through JS

With the development of the Internet, "homology strategy" is becoming more and more strict, not limited to Cookie reading. At present, if non homologous, a total of three behaviors are limited.

(1) Cookie s, LocalStorage, and IndexDB cannot be read.
(2) DOM cannot get.
(3) The requested response was intercepted.

Tips: IndexedDB is a local database provided by the browser, which can be created and operated by web script.
In the past, we generally used cookie s and localStorage or sessionStorage for web page storage. However, one of these two methods has limited storage space, and the other can only establish very simple object settings and obtain properties. IndexedDB can not only store a large amount of data, but also establish indexes and provide search interfaces. It will have great advantages in large projects.

2, Cross domain resource sharing (CORS)

1. Introduction

CORS is a W3C standard. Its full name is "cross origin resource sharing". It helps break through the restriction of browser's homology policy.
When a resource (origin) initiates a request to another resource (host) through a script, and the requested resource (host) and the request source (origin) are different sources (protocol, domain name and port are not all the same), the browser will initiate a cross domain HTTP request, and the browser will automatically add the domain of the current resource to a Header called Origin in the request Header.

There are three tags that allow resources to be loaded across domains:
<img src=XXX>  - Technically,<img> The tag does not insert an image into the web page, but links the image from the web page.<img> The tag creates the footprint of the referenced image.
<link href=XXX> - <link> Tags define the relationship between documents and external resources. The most common use is to link style sheets.
<script src=XXX> - <script> Tags are used to define client-side scripts, such as JavaScript. script Elements can contain either script statements or through src Property points to an external script file.

2. CORS implementation mechanism

Add cross domain related fields in the response, starting with access control allow.

  1. Access control allow origin: this field is required, indicating that the request for the domain name corresponding to this value is accepted.
  2. Access control allow credentials: this value is a Boolean value indicating whether cookies are allowed to be sent. By default, this value is false. This value can only be set to true. If the server does not want the browser to send cookies, delete this field (that is, take the default value). It should be noted that the current end is set to XHR Withcredentials = true when Cookie information is allowed to be carried, access control allow origin cannot be set to *, and an explicit domain name consistent with the requested web page must be specified. At the same time, cookies still follow the same origin policy. Only cookies set with the server domain name will be uploaded, and cookies of other domain names will not be uploaded.
  3. Access control allow headers: the response header access control allow headers is used in the preflight request to list the header information that will appear in the access control expose headers field of the formal request.
  4. Access control expose headers: this field is optional. During CORS request, the getResponseHeader() field of XMLHttpRequest object can only get six basic fields: cache control, content language, content type, Expires, last modified and Pragma. If you want to get values other than these six values, you must specify them in access control expose headers.
  5. Access-Control-Allow-Methods:
    It is used to list the HTTP methods allowed by the browser's CORS request, such as GET, POST, PUT, DELETE and OPTIONS
  6. Access control Max age: used to specify the validity period of this pre inspection request, in seconds. There is no need to send another pre inspection request during this period.

3. Simple request & non simple request

There are differences between simple requests and non simple requests.

Simple request

A CORS simple request is only one that satisfies both of the following conditions.

  1. The request mode is one of HEAD, GET and POST
  2. The information added by the developer in the HTTP header information shall not exceed the following:
  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content type: limited to three values: application/x-www-form-urlencode, multipart / form data, and text/plain

For simple requests, the browser directly sends CORS requests, specifically, adding an Origin field to the header information

Non simple request

Non simple requests are those that have special requirements for the server. For example, the request method is PUT or DELETE, or the content type field type is application/json. For CORS requests that are not simple requests, an HTTP query request will be added before formal communication, which is called preflight. The request method used for preflight requests is OPTIONS.

3, CORS implementation scheme

1. JSONP

Information: http://www.nowamagic.net/librarys/veda/detail/224
Using the vulnerability that the < script > tag does not have cross domain restrictions, web pages can get JSON data dynamically generated from other sources. JSONP requests must be supported by the server of the other party.
JSONP is the same as Ajax. Both clients send requests to the server and obtain data from the server. However, AJAX belongs to the same source policy and JSONP belongs to the non same source policy (supporting cross domain requests). JSONP has the advantages of simplicity and good compatibility. It can be used to solve the problem of cross domain data access of mainstream browsers. The disadvantage is that only GET method is supported, which is limited, unsafe and may be subject to XSS attack.

2. Reverse proxy server

The implementation of CORS by reverse proxy server does not strongly depend on the framework, and the programs developed by any language and framework can be implemented.
nginx configuration reference,

#
# Wide-open CORS config for nginx
#
location / {
	
	#### For OPTIONS requests, many request headers will be set and 204 will be returned
     if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        #
        # Custom headers and headers various browsers *should* be OK with but aren't
        #
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        #
        # Tell client that this pre-flight info is valid for 20 days
        #
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
     }
     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
}

3. The server implements CORS

The safest thing is for the server to set which sources of requests are allowed, that is, after receiving the request, the server sets the response header of access control allow origin for the allowed request sources.

① Filter
@Component
@WebFilter(urlPatterns = "/*", filterName = "CorsFilter")
public class CorsFilter implements Filter {
 
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest reqs = (HttpServletRequest) req;
        String curOrigin = reqs.getHeader("Origin");
        response.setHeader("Access-Control-Allow-Origin", curOrigin == null ? "true" : curOrigin);
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        chain.doFilter(req, res);
    }
 
    @Override
    public void init(FilterConfig filterConfig) {}
 
    @Override
    public void destroy() {}
② @CrossOrigin

Principle link: @CrossOrigin implementation principles
You can directly add the @ CrossOrigin annotation on the @ RequestMapping annotation and its sub implementation annotation modified method / controller class to enable CORS. It is essentially an interceptor.

// Annotate methods---------------------------
@RestController
@RequestMapping("/account")
public class AccountController {

	@CrossOrigin
	@GetMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}

// Annotate the control class---------------------------
@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

	@GetMapping("/{id}")
	public Account retrieve(@PathVariable Long id) {
		// ...
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {
		// ...
	}
}
③ Spring framework injects cross domain configuration classes (recommended)

Annotations need to be too troublesome one by one. How to implement CORS when requesting a specified path through the configuration class?
Examples are taken from the official website: https://docs.spring.io/spring-framework/docs/5.3.9/reference/html/web.html#mvc-cors-filter

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {

        registry.addMapping("/api/**")
            .allowedOrigins("https://domain2.com")
            .allowedMethods("PUT", "DELETE")
            .allowedHeaders("header1", "header2", "header3")
            .exposedHeaders("header1", "header2")
            .allowCredentials(true).maxAge(3600);

        // Add more mappings...
    }
}

reference material:
https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy
https://baike.baidu.com/item/%E5%90%8C%E6%BA%90%E7%AD%96%E7%95%A5/3927875?fr=aladdin
https://zhuanlan.zhihu.com/p/145837536
https://spring.io/blog/2015/06/08/cors-support-in-spring-framework
https://zhuanlan.zhihu.com/p/145837536
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Vary
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
https://blog.51cto.com/u_3631118/3121686?xiangguantuijian&01
https://blog.51cto.com/u_3631118/3121688
https://blog.51cto.com/u_3631118/3124570?xiangguantuijian&06

Topics: Java