Skip to content
返回质量保障

安全头

设锁定浏览器的 HTTP 响应头: CSP、HSTS、X-Frame-Options 等。

为什么

安全头是浏览器侧控制,几行配置防整类攻击。Content-Security-Policy 通过限制脚本加载源止 XSS——即使攻击者注入 <script> 标签浏览器也拒执行。HSTS 强制 HTTPS 防 SSL 剥离降级。X-Frame-Options 通过禁你页被框防点击劫持。这些头免费,在边缘(Nginx、Cloudflare 或框架中间件)设一次,保护每个响应无需任何代码改。它们是最高 ROI 安全控制: 几小时配置防代码中要数周修的攻击。

何时使用

首次生产部署前设安全头并在每次 staging 部署验。新功能加外部资源(第三方脚本、CDN 字体、iframe 嵌入)时审。

如何做

1. 设 Content-Security-Policy(CSP)——最重要的头
   - 先 report-only 模式: Content-Security-Policy-Report-Only
   - 收违规报告,调策略直到无合法流量被阻
   - 然后强制: script-src 'self' + 特定可信源;无 'unsafe-inline'

2. 设传输和框头
   - Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
   - X-Frame-Options: DENY(或 CSP frame-ancestors 'none'——现代等价)
   - X-Content-Type-Options: nosniff(防 MIME 嗅探)

3. 设隐私和引用头
   - Referrer-Policy: strict-origin-when-cross-origin(少泄露给第三方)
   - Permissions-Policy: camera=(), microphone=(), geolocation=()(禁未用 API)
   - Cross-Origin-Opener-Policy: same-origin(隔离浏览上下文)

4. 在边缘或框架中间件配
   - Nginx: server 块中 add_header
   - Cloudflare: Transform Rules 或 Workers
   - Next.js: next.config.js headers() 或 middleware
   - Helmet(Express): app.use(helmet()) 设合理默认

5. 用扫描器和头检查工具验
   - securityheaders.com 或 Mozilla Observatory——目标 A+ 级
   - ZAP 被动扫标缺/错配头
   - 测 CSP 不破合法功能(第三方脚本、内联样式)

示例

# Nginx: /etc/nginx/sites-enabled/app.conf
server {
    listen 443 ssl http2;
    server_name example.com;

    add_header Content-Security-Policy
      "default-src 'self'; \
       script-src 'self' https://plausible.io; \
       style-src 'self' 'unsafe-inline'; \
       img-src 'self' data: https:; \
       connect-src 'self' https://api.example.com; \
       frame-ancestors 'none'; \
       base-uri 'self'; \
       form-action 'self'" always;

    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
}

# Next.js: next.config.js
const cspHeader = [
  "default-src 'self'",
  "script-src 'self' https://plausible.io",
  "style-src 'self' 'unsafe-inline'",
  "img-src 'self' data: https:",
  "frame-ancestors 'none'",
].join("; ");

module.exports = {
  async headers() {
    return [{
      source: "/(.*)",
      headers: [
        { key: "Content-Security-Policy", value: cspHeader },
        { key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
        { key: "X-Content-Type-Options", value: "nosniff" },
      ],
    }];
  },
};

常见问题

  • ⚠CSP script-src 设 'unsafe-inline' 避破内联脚本——这禁了 CSP 本该提供的 XSS 保护,不如不设头。
  • ⚠HSTS 用短 max-age(如 3600 = 1 小时)——浏览器一小时后忘策略又易受 SSL 剥离;用 63072000(2 年)含 preload。
  • ⚠错误响应(404、500)忘设头——Nginx add_header 无 always 仅 2xx 设,错误页无 CSP 可利用。
  • ⚠应用永不被合法框时设 X-Frame-Options: SAMEORIGIN——DENY 更严禁所有框,若你完全不用框则对。

最佳实践

  • ✓CSP 先 Report-Only 模式,收一周违规报告,调策略直到无合法流量触发违规——然后强制,不破真实用户。
  • ✓用 'always' 标志(Nginx)或等价使错误响应也设头——无 CSP 的错误页是攻击面,大多错配在非 2xx 响应。
  • ✓用 CSP frame-ancestors 'none' 替 X-Frame-Options(现代等价覆盖所有框非仅同源),两者都设为与旧浏览器纵深防御。
  • ✓每次部署后用 securityheaders.com 或 Mozilla Observatory 验头——被设后静默移除的头是常见回归。