Support >
  About cybersecurity >
  The core logic of Nginx cross-domain configuration is discussed
The core logic of Nginx cross-domain configuration is discussed
Time : 2025-03-24 14:50:34
Edit : Jtti

In Web application development, the front and back end collaboration pain points when cross-region requests are made. When a browser sends a request with a different domain name, port, or protocol, the Same-Origin Policy intercepts the response by default, causing the front-end to be unable to obtain data. Although modern front-end frameworks and back-end languages provide cross-domain solutions, Nginx can deal with cross-domain problems in a unified manner, which can not only reduce code intrusion, but also achieve global control at the gateway layer, especially suitable for complex scenarios such as microservice architecture and multi-project collaboration.

The root cause of cross-domain problems is browser security mechanisms, not server-side communication barriers. Even if the backend API returns data normally, the browser will still intercept the response if the response header does not contain a CORS related field. The core role of Nginx is to explicitly tell the browser which source, method, and header information is allowed for cross-domain access by modifying the response header. The most basic configuration is to add the following directive to the server or location block of Nginx:

nginx
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,Content-Type,Accept,Authorization';

This configuration allows any domain name () to be accessed cross-domain via GET, POST methods, and accepts common request header fields. However, this "all-pass" mode is only suitable for test environments, and production environments must be carefully controlled. For example, the configuration of Access-Control-Allow-Origin on an enterprise open platform allows malicious websites to call its API at will, resulting in data leakage. The correct approach is to dynamically set the allowed domain names:

nginx
set $cors_origin '';
if ($http_origin ~ '^https? ://(localhost:3000|app.example.com)$') {
set $cors_origin $http_origin;
}
add_header 'Access-Control-Allow-Origin' $cors_origin always;

Here, you can use regular expressions to match legitimate sources to avoid security risks caused by wildcards. The always argument ensures that the CORS header is added even if Nginx returns a 4xx/5xx error, preventing the front end from being unable to capture error details due to missing headers.

The handling of Preflight requests is often neglected, resulting in cross-domain configurations being "partially effective." When the request contains a custom header (such as Authorization) or uses methods such as DELETE, PUT, etc., the browser sends the OPTIONS method first for precheck. If Nginx does not handle the OPTIONS request correctly, the browser will reject subsequent actual requests. The solution is to configure the response separately for the OPTIONS method:

nginx
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' $cors_origin;
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization, X-Custom-Header';
add_header 'Access-Control-Max-Age' 1728000;   # Cache for 20 days
add_header 'Content-Type' 'text/plain;  charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
# Other request handling logic
}

This configuration responds directly to the 204 status code, preventing OPTIONS requests from penetrating the back-end service. Access-Control-Max-Age Defines the cache duration of precheck results to reduce duplicate precheck requests. Note that if you use the Nginx proxy WebSocket, you will need to process the Upgrade header extra:

nginx
add_header 'Access-Control-Allow-Headers' 'Upgrade';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';

The configuration of Credentials requires special attention. When withCredentials: true is set on the current end (commonly seen in authentication scenarios with cookies), the server must respond to Access-Control-Allow-Credentials: true, and Access-Control-Allow-Origin cannot be a wildcard (). For example, a single sign-on system needs to strictly limit the allowed domain names:

nginx
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Origin' 'https://sso.example.com';

At the same time, the back-end service must ensure that the SameSite and Secure attributes of cookies are compatible with the CORS configuration to prevent browsers from blocking cookies. The configuration of an e-commerce platform is not synchronized. SameSite=None. Secure, causing the cross-domain login state to become invalid and the user churn rate to increase by 15%.

Header conflicts between the Nginx layer and back-end services are common pitfalls. If a backend service (such as Node.js, Java) also sets the CORS header, and Nginx repeatedly adds the same header, the browser may receive duplicate values resulting in parsing errors. For example:

Access-Control-Allow-Origin: https://app.example.com, https://app.example.com

Such problems can be solved by:

1. Unified management and control: Close the CORS logic of the back-end service and completely handle it by Nginx;

2. Header overwriting: in Nginx, use proxy_hide_header to remove the CORS header returned by the back-end, and then add:

nginx
proxy_hide_header 'Access-Control-Allow-Origin';
proxy_hide_header 'Access-Control-Allow-Methods';
add_header 'Access-Control-Allow-Origin' $cors_origin always;

The cross-domain configuration in dynamic routing and regular matching scenarios requires careful design. For RESTful apis, different paths may correspond to different cross-domain policies. For example, the public API allows access to all domain names, while the management interface is limited to Intranet domain names only:

nginx
location /api/public {
add_header 'Access-Control-Allow-Origin' '' always;
# Other configuration
}
location /api/admin {
if ($http_origin ! ~ '^https? //(admin.internal.com|172.16.0.0/24)$') {
return 403;
}
add_header 'Access-Control-Allow-Origin' $http_origin always;
add_header 'Access-Control-Allow-Methods' 'GET, POST';
}

The $http_origin variable is used to obtain the source of the request dynamically, and the condition judgment is realized with regular expression. It should be noted that the if instruction of Nginx has limitations, and complex logic is recommended to be implemented through the map module:

nginx
map $http_origin $cors_origin {
default "";
~^https? ://(app.example.com|dev.example.net)$ $http_origin;
}

Cache and browser compatibility issues can cause a configuration to "appear to work, but not work." Browsers cache CORS response headers, especially if the Access-Control-Max-Age is long, and the cache must be forcibly refreshed after modifying the Nginx configuration. You can check in the following ways:

1. Chrome Developer Tools checks the Network TAB to see if the response header contains the latest CORS header;

2. The curl command simulates the request to eliminate browser cache interference:

curl -H "Origin: https://test.com" -I https://api.example.com

3. Temporarily set Access-Control-Max-Age to 0 and disable cache for debugging.

For legacy systems or special protocols, such as WebSocket and SSE, you need to adjust the cross-domain policy. WebSocket connections are subject to CORS during the handshake phase, and the Nginx configuration must explicitly allow the Upgrade header:

nginx
location /websocket {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
add_header 'Access-Control-Allow-Origin' 'https://app.example.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Upgrade,Connection';
}

Finally, automated testing and monitoring is a guarantee of continuous reliability. Periodically verify the CORS configuration via Postman or automated scripts and monitor abnormal requests in conjunction with Nginx logs:

nginx
log_format cors_log '$remote_addr - $http_origin - $status';
access_log /var/log/nginx/cors.log cors_log;

Analyze the $http_origin field in logs to identify illegal source requests and adjust security policies in a timely manner.

JTTI-Defl
JTTI-COCO
JTTI-Selina
JTTI-Ellis
JTTI-Eom