Security Headers

HTTP 安全响应头是现代 Web 应用中一道基础且经常被忽视的防御层, 它们作为指令指示浏览器启用 原生保护机制,以抵御各种常见的攻击向量。这些 HTTP 响应头充当一种声明式的安全策略,为浏览器应如何 处理和渲染页面内容、控制脚本执行、 管理 cookies 以及与第三方资源交互制定规则。在正确配置的情况下, 诸如 Content-Security-Policy (CSP)、Strict-Transport-Security (HSTS)、X-Frame-Options 和 X-Content-Type-Options 等响应头能够针对 Cross-Site Scripting (XSS)、 clickjacking、MIME sniffing、协议降级以及恶意代码注入等攻击构筑显著的屏障。正确 实现这些响应头是对 Web 应用进行 hardening 最高效的方式之一, 因为它无需修改应用代码,并能对整类漏洞提供即时保护。 研究表明,绝大多数网站仍未妥善实现 这些响应头,使其用户暴露于本可通过相对 简单的 Web 服务器配置加以缓解的攻击之下。考虑到 自动化安全扫描工具将这些响应头的存在与妥善配置 作为衡量应用安全态势的主要指标,这种疏忽尤为严重。

Content-Security-Policy (CSP)

CSP 通过为 scripts、styles、images 及其他资源定义可信来源的 whitelist 来防范 XSS。

      # 严格的 CSP(推荐)
      Content-Security-Policy:
      default-src 'self';
      script-src 'self' 'nonce-';
      style-src 'self' 'nonce-';
      img-src 'self' https: data:;
      font-src 'self';
      connect-src 'self' https://api.example.com;
      frame-ancestors 'none';
      base-uri 'self';
      form-action 'self';
      # 使用 report-only 的 CSP(测试模式)
      Content-Security-Policy-Report-Only:
      default-src 'self';
      report-uri /csp-violation-report
      

关键的 CSP Directives

  • default-src:其他 directives 的 fallback
  • script-src:JavaScript 执行的 whitelist
  • style-src:允许的 CSS 来源
  • frame-ancestors:防范 clickjacking
  • upgrade-insecure-requests:强制 HTTPS

Strict-Transport-Security (HSTS)

HSTS 强制浏览器始终使用 HTTPS,防范 downgrade attacks 和 SSL stripping。

      # 带 preload 和子域名的 HSTS
      Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
      # HSTS preload 的步骤:
      1. 配置带 preload 的 HSTS 响应头
      2. 在 hstspreload.org 提交域名
      3. 该域名将被纳入浏览器的 preload lists
      

X-Frame-Options

通过控制页面是否可在 frame/iframe 中渲染来防范 clickjacking。

      # 拒绝所有 framing(最安全)
      X-Frame-Options: DENY
      # 仅允许同源
      X-Frame-Options: SAMEORIGIN
      # 允许特定域名(已废弃 - 请使用 CSP frame-ancestors)
      X-Frame-Options: ALLOW-FROM https://trusted.com
      

X-Content-Type-Options

通过强制浏览器遵守所声明的 Content-Type 来防范 MIME sniffing 攻击。

      # 禁用 MIME sniffing
      X-Content-Type-Options: nosniff
      

Referrer-Policy

控制在 requests 中发送多少 referrer information。

      # 推荐策略
      Referrer-Policy: strict-origin-when-cross-origin
      # 选项:
      # - no-referrer:从不发送 referrer
      # - no-referrer-when-downgrade:在 HTTPS→HTTP 时不发送 referrer
      # - same-origin:仅发送给同源
      # - strict-origin:仅发送 origin(不含 path)
      

Permissions-Policy

控制页面可使用哪些 browser features 和 APIs(取代 Feature-Policy)。

      # 禁用危险的功能
      Permissions-Policy:
      geolocation=(),
      microphone=(),
      camera=(),
      payment=(),
      usb=(),
      interest-cohort=()
      

各服务器的配置

Nginx

      # nginx.conf
      add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
      add_header X-Frame-Options "DENY" always;
      add_header X-Content-Type-Options "nosniff" always;
      add_header Referrer-Policy "strict-origin-when-cross-origin" always;
      add_header Content-Security-Policy "default-src 'self';" always;
      add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
      

Apache

      # .htaccess 或 httpd.conf
      Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
      Header always set X-Frame-Options "DENY"
      Header always set X-Content-Type-Options "nosniff"
      Header always set Referrer-Policy "strict-origin-when-cross-origin"
      Header always set Content-Security-Policy "default-src 'self';"
      

Node.js/Express

      // 使用 Helmet middleware
      const helmet = require('helmet');
      app.use(helmet());
      // 自定义配置
      app.use(helmet.contentSecurityPolicy({
      directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "'nonce-'"],
      styleSrc: ["'self'", "'nonce-'"],
      }
      }));
      

测试 Security Headers

  • securityheaders.com:扫描与 A+ 评级
  • Mozilla Observatory:全面分析
  • Chrome DevTools:Network 选项卡 → Headers
  • curl:curl -I https://example.com

常见陷阱

  • CSP 过于宽松,使用了 'unsafe-inline' 和 'unsafe-eval'
  • HSTS 未带 includeSubDomains 使子域名仍可被攻击
  • 响应头已配置但未生效(缺少 always 标志)
  • 仅测试首页 - 响应头应存在于所有页面

完整检查清单

  • [OK] 已配置严格的 Content-Security-Policy
  • [OK] HSTS 设置 max-age 为 1 年 + includeSubDomains
  • [OK] X-Frame-Options:DENY 或 CSP frame-ancestors
  • [OK] X-Content-Type-Options:nosniff
  • [OK] 已配置 Referrer-Policy
  • [OK] Permissions-Policy 禁用未使用的功能
  • [OK] 响应头已在 securityheaders.com 测试(A+ 评级)
  • [OK] CSP 已先用 report-only mode 测试