Nginx handles various problems and solutions encountered by cros across domains, as well as https configuration and browser https insecure problem handling

Article directory


foreword

提示:本人在生产部署服务时遇到一系列跨域问题和https配置问题,特此做以下记录:

Preface 1. What is cross-domain?

Cross-domain means that page a wants to obtain resources of page b. If the protocols, domain names, ports, and subdomain names of pages a and b are different, or page a is an ip address and page b is a domain name address, all access actions are cross-domain. domain, and browsers generally restrict cross-domain access for security reasons, that is, cross-domain resource requests are not allowed.

Preface 2. What are the conditions for cross-domain generation?

注意:跨域限制访问,其实是浏览器的限制。理解这一点很重要。所以,当用java(或者其他语言)调用RESTful api,从来不会报什么跨域错误
insert image description here


Two commonly used methods for cross-domain processing

1. How does springboot deal with cross-domain issues?

1.1 Separate configuration in controller

Add @CrossOrigin cross-domain annotations to each Controller class

1.2 Global configuration in the @configation class

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
    
    
        registry.addMapping("/**")  // 匹配了所有的URL
                .allowedHeaders("*")  // 允许跨域请求包含任意的头信息
                .allowedMethods("*")  // 设置允许的方法
                .allowedOrigins("*")  // 设置允许跨域请求的域名
                .allowCredentials(true);  // 是否允许证书,默认false
    }
}

1.3 Add a response header to the filter

protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
    
    
    res.addHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
    res.addHeader("Access-Control-Allow-Methods", "*");
    res.addHeader("Access-Control-Allow-Headers", "Accept,Authorization,DNT,Content-Type,Referer,User-Agent");
    res.addHeader("Access-Control-Allow-Credentials","true"); // 允许携带验证信息
    chain.doFilter(req, res);
}

2. How does nginx handle cross-domain issues?

2.1 Configure the response header parameters for the Nginx server

When a 403 cross-domain error occurs and the No 'Access-Control-Allow-Origin' header is present on the requested resource, you need to configure the response header parameters for the Nginx server.

location / {
    
      
    add_header Access-Control-Allow-Origin *; //允许所有请求访问
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; //允许访问的请求类型
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
	//预检请求需要用到
    if ($request_method = 'OPTIONS') {
    
    
        return 204;
    }
}

2.2. Detailed interpretation of each parameter

  1. Access-Control-Allow-Origin
服务器默认是不被允许跨域的,给Nginx服务器配置`Access-Control-Allow-Origin *`后,表示服务器可以接受所有的请求源(Origin),即接受所有跨域的请求。
  1. Access-Control-Allow-Headers is to prevent the following errors:
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

This error indicates that the value of the current request Content-Type is not supported. In fact, it was caused by us initiating a type request of "application/json". A concept is involved here: preflight request (preflight request), please see the introduction of "preflight request" below.

  1. Access-Control-Allow-Methods is to prevent the following error:
    Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

  2. Adding a 204 return to OPTIONS is to deal with the error that Nginx still refuses access when sending a POST request

发送"预检请求"时,需要用到方法 OPTIONS ,所以服务器需要允许该方法。

Nginx configuration domain name spans multiple domain names

Method 1: Use nginx built-in variables (commonly used)

server {
    
    
        set $cors '';
        if ($http_origin ~* "^http://deomain01:port$") {
    
    
            set $cors $http_origin;
        }
        if ($http_origin ~* "^http://deomain02:port$") {
    
    
            set $cors $http_origin;
        }
        if ($http_origin ~* "^http://deomain002:port$") {
    
    
            set $cors $http_origin;
        }
        location /live{
    
    
                  ...
                add_header 'Access-Control-Allow-Origin' '$cors';
                add_header 'Access-Control-Allow-Credentials' 'true';
                # 为预检请求加的header
                add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE';
                #为预检请求加的header
                add_header 'Access-Control-Allow-Headers' '*';
        }

Explanation: The format of $http_origin is for nginx to take the value of XXX in the header of the request.
The origin is taken here, and the general cross-domain request will put the source of the request in origin (the browser will add the header of origin to the header of the cross-domain request) $ cors
variable gets the desired cross-domain domain name and assigns it to " add_header 'Access-Control-Allow-Origin' '$cors'".

Method 2: use map

  map $http_origin $cors_list{
    
    
		default  http://aaa.cn;
	    "~ http://bbb.cn"  http://bbb.cn;
	}
    server {
    
    
        listen       8089;
        server_name  localhost;
        location /live{
    
    
                  ...
                add_header 'Access-Control-Allow-Origin' '$cors_list';
                add_header 'Access-Control-Allow-Credentials' 'true';
                # 为预检请求加的header
                add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE';
                #为预检请求加的header
                add_header 'Access-Control-Allow-Headers' '*';
        }

Explanation:
The map command is provided by the ngx_http_map_module module, which is loaded by nginx by default.

语法: map $var1 $var2 {
    
    }
默认值: -
配置段: http

map为一个变量设置的映射表。映射表由两列组成,匹配模式和对应的值。

在map块里的参数指定了源变量值和结果值的对应关系。

default: 没有匹配结果将使用的默认值。如果没有设置default,将会用一个空的字符串作为默认的结果。

匹配模式可以是一个简单的字符串或者正则表达式,使用正则表达式要用(‘~’)

Method 3: Regular matching of third-level domain names

   location / {
    
    

             if ($http_origin ~* (http?://.*\.aliuncle\.top$)) {
    
    
                    add_header Access-Control-Allow-Origin $http_origin;
            }
            index index.php;
            try_files $uri $uri/ /index.php?$args;
    }

Note: When configuring cross-domain in the nginx.conf configuration file, remember to clear the client such as the browser cache, otherwise the configuration will not take effect.

2.3, nginx handles various error reports encountered in the cross-domain process

1. The cross-domain request cannot carry the identity credential cookie error ()

insert image description here

Description of the problem: The identity credential cookie cannot be passed in the request anyway

Solution:
front-end:
1. Set the attribute withCredentials of the request object to true when the front-end requests;
insert image description here

2. The backend supports the response header Credentials as true
insert image description here
注意:除了 Access-Control-Allow-Credentials 之外,跨域发送 Cookie 还要求 Access-Control-Allow-Origin 不允许使用通配符。 事实上不仅不允许通配符,而且 只能指定单一域名:
, otherwise a cros error will be reported
insert image description here

2.4, preflight request (preflight request) error

insert image description here

Introduction:
The Cross-Origin Resource Sharing (CORS) standard adds a new set of HTTP header fields, allowing the server to declare which origin sites have permission to access which resources. In addition, the specification requires that for those HTTP request methods that may have side effects on server data (especially HTTP requests other than GET, or POST requests with certain MIME types ), the browser must first use the OPTIONS method to initiate a preflight request ( preflight request), so as to know whether the server allows the cross-domain request. After the server confirms the permission, the actual HTTP request is initiated. In the return of the preflight request, the server can also notify the client whether to carry identity credentials (including Cookies and HTTP authentication related data).
In fact, the request whose Content-Type field is application/json is the above-mentioned POST request with certain MIME types. CORS stipulates that Content-Types that do not belong to the following MIME types are all pre-check requests:

application/x-www-form-urlencoded
multipart/form-data
text/plain

2.4.1. Expected request process (send options request/response first, then send post request)

insert image description here

2.4.2, pre-check request error

Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

Explanation:
The application/json request will add a "pre-check" request before the formal communication. This "pre-check" request will bring header information. When the server responds, if the returned header information does not contain Access-Control -Allow-Headers: Content-Type indicates that non-default Content-Type is not accepted. That is, the above error occurs:

预检请求头信息
Access-Control-Request-Headers: Content-Type:
OPTIONS /api/test HTTP/1.1
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type

2.4.3. How to solve the error report of the pre-check request?

The preflight request was also mentioned earlier, we only need to add our judgment before the nginx proxy to make nginx return a processing success status code when it encounters an options request

//预检请求需要用到
    if ($request_method = 'OPTIONS') {
    
    
        return 204;
    }

Detailed explanation of nginx status code

Detailed explanation of http

2.4.4 Access-Control-Allow-Origin can only be set once, after configuration in the backend, it cannot be configured again in nginx

The following error is reported:
insert image description here
Explanation: The Access-Control-Allow-Origin value returned by the server should not be a list, because the browser will only accept one value, and it cannot be empty.

2.5. The request header carries additional information such as Authorization

insert image description here

报错:(Request header field authorization is not allowed by Access-Control-Allow-Headers in preflight)

2.5.1, Explanation

The response header Access-Control-Allow-Headers is used in the preflight request (preflight request), and lists the header information that will appear in the Access-Control-Request-Headers field of the formal request. Simple headers, such as simple headers, Accept, Accept-Language, Content-Language, Content-Type (limited to the three MIME values ​​of application/x-www-form-urlencoded, multipart/form-data or text/plain after parsing type (excluding parameters)), they are always supported and do not need to be specifically listed in this header.

Additional request header information such as Authorization and x-token needs to be allowed. This error is reported through request preprocessing to know that the request header Authorization is not allowed, so it reports a cross-domain

2.5.2. Solve

It is necessary to add the allowed header Authorization, and when it is judged that the request method is options, return ok (200) to the client, so that the formal post request can continue.

    add_header 'Access-Control-Allow-Origin' '*' always;
    add_header 'Access-Control-Allow-Credentials' 'true';
    add_header 'Access-Control-Allow-Methods' 'GET, POST, PATCH, DELETE, PUT, OPTIONS';
	add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type, X-Custom-Header, Access-Control-Expose-Headers, Token, Authorization';
	add_header 'Access-Control-Allow-Headers'  '*';
    add_header 'Access-Control-Max-Age' 1728000;

2.6. In-depth analysis and resolution of cross-domain errors in the new version of Google: request client is not a secure context and the resource is in more-private address

2.6.1 Reasons for error reporting

Error: An insecure requester requested a more private local resource
insert image description here

Reason: Starting from version 94 of Google, Google has updated the private network for unsafe websites to block such requests to access more private resources. At the same time, before requesting private network resources, an OPTIONS preflight request will be sent first.

2.6.2 Solutions

1. Replace non-Google kernel browsers (using Firefox, edge, etc.) or lower the version

2. Modify the settings of Google Chrome Solution
: Disable the settings. For Google Chrome versions between 94 and 101, you can modify the browser settings so that requests for private resources sent by http websites can be successfully sent.

Proceed as follows:

Step 1: Enter in the browser: chrome://flags/#block-insecure-private-network-requests

Step 2: Change the Default of the Block insecure private network requests. item to Disabled, and restart the browser (different versions have different configurations, please refer to the following reference link for details). Refer to link 3. Modify the access method of intranet pictures and other resources
insert image description here
,
all Using https access can fundamentally solve the problem

How to configure https (configure ssl in nginx)

1. Configuration

Summarize the following steps: apply for ssl->ssl file storage to the server->nginx configure ssl

  server {
    
    
                listen       8002 ssl;          
                server_name temp.3zyun.com ;   #公网ip      115.148.208.122                                       
                client_max_body_size 1024M;
                ssl_certificate /usr/local/nginx/yjssl/7604469_temp.3zyun.com_nginx/7604469_temp.3zyun.com.pem;
        ssl_certificate_key /usr/local/nginx/yjssl/7604469_temp.3zyun.com_nginx/7604469_temp.3zyun.com.key;
        ssl_session_cache    shared:SSL:1m;
        ssl_session_timeout  5m;
        ssl_ciphers  HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers  on ;
                location / {
    
    
                         
                        proxy_pass http://bpm-server/;
                        proxy_set_header Host $host:$server_port;
                }
        }

注意 :端口后面要加上ssl才可生效
The ssl configuration was inspired by this article

2. A series of problems encountered

2.1. The h5 project is packaged and deployed to production

Mixed Content: The page at 'xxx' was loaded over HTTPS, but requested an insecure resource 'xxx'. This request has been blocked; the content must be served over HTTPS Problem solving explanation: When our browser appears similar to "was
insert image description here
loaded over HTTPS, but requested an insecure resource/frame" error is generally because our website is HTTPS, and the other party's link is HTTP protocol, so when Ajax or javascript requests, it will report the above Error, if requesting http interface or importing http resources in https will be directly blocked (blocked), the browser defaults to this behavior as unsafe and will block it.

Solution:

(在index.html的head中加入以下代码)
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />

Function: The principle of adding this tag is to use the META tag to forcibly convert http requests into https (SSL protocol) requests.

Summarize

Always grow after constantly stepping on the pit! ! !

Guess you like

Origin blog.csdn.net/wei1359765074410/article/details/127510086