# CORS / CSP / 安全 Header 全套审计与改进 **审计日期**: 2026-06-15 **审计人**: Claude(满载跑批) **关联**: [[风险跟踪表]] / [[后端架构]] / [[外部系统集成]] --- ## 📌 1. 现状盘点 ### 1.1 后端 CORS 配置(`backend/app/main.py:363`) ```python app.add_middleware( CORSMiddleware, allow_origins=settings.cors_origins_list, # 逗号分隔的列表 allow_credentials=True, allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], allow_headers=["Authorization", "Content-Type", "X-Employee-Id"], ) ``` **当前 `cors_origins`**: - 默认: `localhost:5173,5174,5175`(开发) - 生产: `itsupport.servyou.com.cn`(.env.production) ### 1.2 Nginx 安全头(`nginx.conf` + `nginx-nas.conf`) **已有**: ```nginx add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-XSS-Protection "1; mode=block" always; ``` **缺失**: - `Strict-Transport-Security` (HSTS) - `Content-Security-Policy` (CSP) - `Referrer-Policy` - `Permissions-Policy` - `Cross-Origin-*` 系列 ### 1.3 问题清单 | # | 问题 | 严重度 | 风险 | |---|---|---|---| | C-1 | CORS `allow_origins` 默认含 `*`(环境切换不当会泄露) | 🟠 | 跨域未授权 | | C-2 | CORS 没限制 `expose_headers`(前端拿不到 trace_id) | 🟡 | 排障不便 | | C-3 | CORS `max_age` 未设(每次预检) | 🟢 | 性能 | | C-4 | nginx 缺 HSTS | 🟠 | 中间人降级 | | C-5 | nginx 缺 CSP | 🟠 | XSS | | C-6 | nginx 缺 Referrer-Policy | 🟡 | 信息泄露 | | C-7 | nginx 缺 Permissions-Policy | 🟡 | 设备 API 滥用 | | C-8 | nginx 缺 COOP/COEP | 🟡 | 跨源攻击 | | C-9 | `/api/wecom/callback` 没限 IP | 🟡 | 恶意回调 | | C-10 | 4 前端没 CSP meta(防 XSS) | 🟠 | XSS | --- ## 📌 2. CORS 改进 ### 2.1 后端 - 精细化 CORS **新建 `backend/app/utils/cors_config.py`**: ```python from typing import List from app.config import settings def build_cors_config() -> dict: """根据环境构建 CORS 配置""" is_prod = settings.backend_env == "production" # 需新增环境变量 if is_prod: # 生产:严格白名单 origins = [ o.strip() for o in settings.cors_origins.split(",") if o.strip() and not o.startswith("*") ] return { "allow_origins": origins, "allow_credentials": True, "allow_methods": ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], "allow_headers": [ "Authorization", "Content-Type", "X-Employee-Id", "X-Request-ID", # trace_id "X-CSRF-Token", # CSRF 防护 "X-Agent-Id", # 坐席 ID ], "expose_headers": [ "X-Request-ID", # 暴露 trace_id "X-RateLimit-Remaining", # 限流剩余 "X-RateLimit-Reset", # 限流重置 ], "max_age": 600, # 10 分钟预检缓存 } # 开发:宽松 return { "allow_origins": settings.cors_origins_list, "allow_credentials": True, "allow_methods": ["*"], "allow_headers": ["*"], "expose_headers": ["*"], "max_age": 3600, } ``` **更新 `main.py`**: ```python from app.utils.cors_config import build_cors_config cors_config = build_cors_config() app.add_middleware( CORSMiddleware, **cors_config, ) ``` ### 2.2 新增环境变量 **`backend/app/config.py`**: ```python # 新增 backend_env: str = "development" # development / production ``` **`.env.production`**: ```bash BACKEND_ENV=production CORS_ORIGINS=https://itsupport.servyou.com.cn ``` ### 2.3 CORS 验证脚本 ```bash # 验证 CORS 头 curl -I -X OPTIONS \ -H "Origin: https://itsupport.servyou.com.cn" \ -H "Access-Control-Request-Method: POST" \ -H "Access-Control-Request-Headers: Authorization" \ http://localhost:8000/api/v1/auth/login # 期望响应: # Access-Control-Allow-Origin: https://itsupport.servyou.com.cn # Access-Control-Allow-Credentials: true # Access-Control-Max-Age: 600 ``` --- ## 📌 3. Nginx 安全 Header 完整套 ### 3.1 完整版 nginx.conf(替换安全头部分) ```nginx # ================================================================= # 安全响应头配置(全部) # ================================================================= # 1. HSTS - 强制 HTTPS(2 年,包含子域名) add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; # 2. CSP - 内容安全策略(严格版,API 网关除外) # 注意:API 路径不要 CSP(纯 JSON),只 HTML 路径需要 location /itdesk/ { # 基础 CSP add_header Content-Security-Policy " default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://res.wx.qq.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob: https: http:; font-src 'self' data:; connect-src 'self' https://qyapi.weixin.qq.com wss://* https://*.servyou-it.com; media-src 'self' blob:; object-src 'none'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests; " always; alias /usr/share/nginx/html/itdesk/; # ... } # 3. 防 MIME 嗅探 add_header X-Content-Type-Options "nosniff" always; # 4. 防点击劫持(更严:拒绝所有 frame 嵌入) add_header X-Frame-Options "DENY" always; # 5. XSS 过滤器(现代浏览器已废弃,保留向后兼容) add_header X-XSS-Protection "0" always; # 0 = 关闭(CSP 已接管) # 6. Referrer 策略(API 不发送 referrer,HTML 限制来源) add_header Referrer-Policy "strict-origin-when-cross-origin" always; # 7. Permissions Policy(禁用不用的设备 API) add_header Permissions-Policy " camera=(), microphone=(), geolocation=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=() " always; # 8. 跨源隔离 add_header Cross-Origin-Opener-Policy "same-origin" always; add_header Cross-Origin-Embedder-Policy "require-corp" always; add_header Cross-Origin-Resource-Policy "same-origin" always; # 9. 服务器信息隐藏 server_tokens off; # 隐藏 nginx 版本 # 10. API 路径特殊头(API 不需要 CSP,但要 CORS 友好) location /api/ { # 移除 CSP(API 返回 JSON,不要 CSP) more_clear_headers "Content-Security-Policy"; # API 也加 HSTS add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; add_header X-Content-Type-Options "nosniff" always; add_header Cache-Control "no-store" always; # API 禁止缓存 proxy_pass http://backend_api/; # ... } ``` ### 3.2 完整版 nginx-nas.conf(同上,Cloudflare 适配) ```nginx # Cloudflare Tunnel 已经在外层 HTTPS,这里加全头 add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header X-XSS-Protection "0" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always; add_header Cross-Origin-Opener-Policy "same-origin" always; add_header Cross-Origin-Embedder-Policy "require-corp" always; add_header Cross-Origin-Resource-Policy "same-origin" always; server_tokens off; ``` --- ## 📌 4. 前端 CSP Meta(双保险) ### 4.1 4 前端 `index.html` 加 meta CSP **`frontend-admin/index.html`**: ```html