fix: deduplicate proxied security headers
This commit is contained in:
@@ -78,12 +78,17 @@ test('前端 package.json 与 lock 文件依赖同步且没有手工缓存版本
|
||||
test('生产部署统一使用 Vite dist 且不会删除 lock 文件', () => {
|
||||
const installer = fs.readFileSync(path.join(projectRoot, 'install.sh'), 'utf8');
|
||||
const nginxConfig = fs.readFileSync(path.join(projectRoot, 'nginx', 'nginx.conf'), 'utf8');
|
||||
const nginxExample = fs.readFileSync(path.join(projectRoot, 'nginx', 'nginx.conf.example'), 'utf8');
|
||||
assert.ok(installer.includes('npm ci --include=dev'));
|
||||
assert.ok(installer.includes('npm run build'));
|
||||
assert.ok(installer.includes('frontend/dist'));
|
||||
assert.strictEqual(/rm\s+-rf\s+node_modules\s+package-lock\.json/.test(installer), false);
|
||||
assert.ok(nginxConfig.includes('root /usr/share/nginx/html;'));
|
||||
assert.ok(nginxConfig.includes('alias /runtime/downloads/;'));
|
||||
for (const config of [installer, nginxConfig, nginxExample]) {
|
||||
assert.ok(config.includes('proxy_hide_header X-Request-ID;'));
|
||||
assert.ok(config.includes('proxy_hide_header Content-Security-Policy;'));
|
||||
}
|
||||
});
|
||||
|
||||
test('Docker 构建上下文排除依赖、环境配置和运行时数据', () => {
|
||||
|
||||
63
install.sh
63
install.sh
@@ -2407,6 +2407,16 @@ server {
|
||||
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
|
||||
# 对外安全头由 Nginx 统一输出,避免与后端重复
|
||||
proxy_hide_header X-Frame-Options;
|
||||
proxy_hide_header X-Content-Type-Options;
|
||||
proxy_hide_header X-XSS-Protection;
|
||||
proxy_hide_header Referrer-Policy;
|
||||
proxy_hide_header Permissions-Policy;
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
proxy_hide_header X-Request-ID;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
|
||||
# 隐藏Nginx版本号
|
||||
server_tokens off;
|
||||
|
||||
@@ -2707,6 +2717,16 @@ server {
|
||||
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
|
||||
# 对外安全头由 Nginx 统一输出,避免与后端重复
|
||||
proxy_hide_header X-Frame-Options;
|
||||
proxy_hide_header X-Content-Type-Options;
|
||||
proxy_hide_header X-XSS-Protection;
|
||||
proxy_hide_header Referrer-Policy;
|
||||
proxy_hide_header Permissions-Policy;
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
proxy_hide_header X-Request-ID;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
|
||||
# 隐藏Nginx版本号
|
||||
server_tokens off;
|
||||
|
||||
@@ -2857,6 +2877,16 @@ server {
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# 对外安全头由 Nginx 统一输出,避免与后端重复
|
||||
proxy_hide_header X-Frame-Options;
|
||||
proxy_hide_header X-Content-Type-Options;
|
||||
proxy_hide_header X-XSS-Protection;
|
||||
proxy_hide_header Referrer-Policy;
|
||||
proxy_hide_header Permissions-Policy;
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
proxy_hide_header X-Request-ID;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
|
||||
# 隐藏Nginx版本号
|
||||
server_tokens off;
|
||||
|
||||
@@ -3621,6 +3651,35 @@ update_migrate_nginx_config() {
|
||||
mv "$secured_file" "$config_file"
|
||||
fi
|
||||
|
||||
if ! grep -q "proxy_hide_header X-Request-ID" "$config_file"; then
|
||||
local proxy_headers_file="${config_file}.proxy-headers.$$"
|
||||
if ! awk '
|
||||
/add_header Content-Security-Policy/ && !inserted_proxy_headers {
|
||||
print
|
||||
print ""
|
||||
print " # 对外安全头由 Nginx 统一输出,避免与后端重复"
|
||||
print " proxy_hide_header X-Frame-Options;"
|
||||
print " proxy_hide_header X-Content-Type-Options;"
|
||||
print " proxy_hide_header X-XSS-Protection;"
|
||||
print " proxy_hide_header Referrer-Policy;"
|
||||
print " proxy_hide_header Permissions-Policy;"
|
||||
print " proxy_hide_header Strict-Transport-Security;"
|
||||
print " proxy_hide_header X-Request-ID;"
|
||||
print " proxy_hide_header Content-Security-Policy;"
|
||||
inserted_proxy_headers = 1
|
||||
next
|
||||
}
|
||||
{ print }
|
||||
END { if (!inserted_proxy_headers) exit 2 }
|
||||
' "$config_file" > "$proxy_headers_file"; then
|
||||
rm -f "$proxy_headers_file"
|
||||
print_error "无法为 Nginx 配置添加上游响应头去重: $config_file"
|
||||
cp -a "$backup_dir/$backup_name" "$config_file"
|
||||
return 1
|
||||
fi
|
||||
mv "$proxy_headers_file" "$config_file"
|
||||
fi
|
||||
|
||||
if ! grep -q "location /downloads/" "$config_file"; then
|
||||
local migrated_file="${config_file}.migrate.$$"
|
||||
awk -v project_dir="$PROJECT_DIR" '
|
||||
@@ -3638,7 +3697,9 @@ update_migrate_nginx_config() {
|
||||
mv "$migrated_file" "$config_file"
|
||||
fi
|
||||
|
||||
if ! grep -q "root ${PROJECT_DIR}/frontend/dist;" "$config_file" || ! grep -q "location /downloads/" "$config_file"; then
|
||||
if ! grep -q "root ${PROJECT_DIR}/frontend/dist;" "$config_file" || \
|
||||
! grep -q "location /downloads/" "$config_file" || \
|
||||
! grep -q "proxy_hide_header X-Request-ID" "$config_file"; then
|
||||
print_error "无法安全迁移 Nginx 配置: $config_file"
|
||||
cp -a "$backup_dir/$backup_name" "$config_file"
|
||||
return 1
|
||||
|
||||
@@ -13,6 +13,16 @@ server {
|
||||
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
|
||||
# 对外安全头由 Nginx 统一输出,避免与后端重复
|
||||
proxy_hide_header X-Frame-Options;
|
||||
proxy_hide_header X-Content-Type-Options;
|
||||
proxy_hide_header X-XSS-Protection;
|
||||
proxy_hide_header Referrer-Policy;
|
||||
proxy_hide_header Permissions-Policy;
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
proxy_hide_header X-Request-ID;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
|
||||
# 隐藏Nginx版本
|
||||
server_tokens off;
|
||||
|
||||
|
||||
@@ -52,6 +52,16 @@ server {
|
||||
add_header Permissions-Policy "camera=(), geolocation=(), microphone=()" always;
|
||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https:; font-src 'self' data:; media-src 'self' blob: https:; connect-src 'self' https: ws: wss:; worker-src 'self' blob:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self';" always;
|
||||
|
||||
# 对外安全头由 Nginx 统一输出,避免与后端重复
|
||||
proxy_hide_header X-Frame-Options;
|
||||
proxy_hide_header X-Content-Type-Options;
|
||||
proxy_hide_header X-XSS-Protection;
|
||||
proxy_hide_header Referrer-Policy;
|
||||
proxy_hide_header Permissions-Policy;
|
||||
proxy_hide_header Strict-Transport-Security;
|
||||
proxy_hide_header X-Request-ID;
|
||||
proxy_hide_header Content-Security-Policy;
|
||||
|
||||
# 隐藏 Nginx 版本
|
||||
server_tokens off;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user