强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

HTTP 协议详解教程 / 第 16 章:HTTP 安全

第 16 章:HTTP 安全

安全是 Web 应用的生命线。本章全面介绍 HTTPS/TLS、各种安全头部以及常见攻击的防御手段。


16.1 HTTPS 与 TLS

为什么需要 HTTPS

威胁HTTPHTTPS
窃听✗ 明文传输✓ 加密传输
篡改✗ 可被修改✓ 完整性校验
冒充✗ 无法验证身份✓ 证书验证

TLS 握手流程(TLS 1.3)

客户端                                服务器
  │                                    │
  │── ClientHello ──────────────────→│
  │   支持的密码套件、密钥共享         │
  │                                    │
  │←── ServerHello + Certificate ────│
  │   选定密码套件、证书、密钥共享     │
  │                                    │
  │── Finished ─────────────────────→│
  │   密钥确认                        │
  │                                    │
  │←══ 加密通信 ════════════════════│

TLS 1.2 vs TLS 1.3

特性TLS 1.2TLS 1.3
握手延迟2 RTT1 RTT
0-RTT不支持支持
密码套件多种精简(仅 5 种)
前向保密可选强制
废弃算法SHA-1、RC4 等移除

16.2 Let’s Encrypt 证书

使用 certbot 获取证书

# 安装 certbot
sudo apt install certbot python3-certbot-nginx

# 获取证书
sudo certbot --nginx -d example.com -d www.example.com

# 自动续期
sudo certbot renew --dry-run

# 设置自动续期 cron
0 0 1 * * certbot renew --quiet

证书验证类型

类型验证内容签发时间适用场景
DV域名所有权分钟级个人网站、API
OV组织信息1-3 天企业网站
EV严格验证1-2 周金融、电商

16.3 HSTS(HTTP Strict Transport Security)

原理

# 服务器告诉浏览器:未来只能用 HTTPS 访问
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

攻击场景与防护

# 没有 HSTS:
1. 用户输入 example.com
2. 浏览器访问 http://example.com
3. 攻击者在 HTTP 请求时进行中间人攻击
4. 即使服务器重定向到 HTTPS,攻击已经发生

# 有 HSTS:
1. 首次访问后,浏览器记住 HSTS 策略
2. 之后输入 example.com,浏览器直接访问 HTTPS
3. 根本不发送 HTTP 请求,消除攻击窗口

Nginx 配置

server {
    listen 443 ssl;
    server_name example.com;
    
    # HSTS 头部
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}

# HTTP 重定向到 HTTPS
server {
    listen 80;
    server_name example.com;
    return 301 https://$host$request_uri;
}

HSTS 参数

参数说明
max-age策略有效期(秒)
includeSubDomains包含子域名
preload加入浏览器预加载列表

16.4 CSP(Content Security Policy)

原理

CSP 限制页面可以加载的资源来源,防止 XSS 攻击。

配置示例

# 基础 CSP
Content-Security-Policy: default-src 'self'

# 完整 CSP
Content-Security-Policy: 
    default-src 'self';
    script-src 'self' https://cdn.example.com 'nonce-abc123';
    style-src 'self' 'unsafe-inline';
    img-src 'self' data: https:;
    font-src 'self' https://fonts.gstatic.com;
    connect-src 'self' https://api.example.com;
    frame-src 'none';
    object-src 'none';
    base-uri 'self';
    form-action 'self';
    upgrade-insecure-requests;

CSP 指令

指令说明示例
default-src默认资源策略'self'
script-srcJavaScript'self' 'nonce-xxx'
style-srcCSS'self' 'unsafe-inline'
img-src图片'self' data: https:
connect-srcAJAX/WebSocket'self' https://api.*
frame-srciframe'none'

防止 XSS

<!-- CSP 阻止内联脚本 -->
<script>alert('XSS')</script>  <!-- 被 CSP 阻止 -->

<!-- 使用 nonce 的安全脚本 -->
<script nonce="abc123">
    // 只有带正确 nonce 的脚本才能执行
    console.log('安全的脚本');
</script>

CSP 报告

# 仅报告模式(不阻止)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report

# 报告模式 + 执行
Content-Security-Policy: default-src 'self'; report-uri /csp-report

16.5 其他安全头部

安全头部一览

头部说明推荐值
X-Content-Type-Options禁止 MIME 嗅探nosniff
X-Frame-Options防止点击劫持DENYSAMEORIGIN
X-XSS-ProtectionXSS 过滤器1; mode=block
Referrer-Policy控制 Refererstrict-origin-when-cross-origin
Permissions-Policy功能权限camera=(), microphone=()

Nginx 完整安全配置

server {
    listen 443 ssl http2;
    server_name example.com;
    
    # TLS 配置
    ssl_certificate /etc/ssl/certs/example.pem;
    ssl_certificate_key /etc/ssl/private/example.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    
    # 安全头部
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.example.com" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "DENY" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
}

16.6 中间人攻击防护

常见攻击类型

攻击说明防御
SSL 剥离强制降级到 HTTPHSTS
证书伪造使用伪造证书证书固定(Certificate Pinning)
DNS 劫持DNS 返回错误 IPDNSSEC / DoH
ARP 欺骗局域网 ARP 表污染HTTPS

Certificate Transparency

# 证书透明度日志
# 所有公开信任的证书都必须记录到 CT 日志
# 浏览器验证 SCT(Signed Certificate Timestamp)
Expect-CT: max-age=86400, enforce, report-uri="/ct-report"

# 安全的 Cookie 配置
Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600
属性作用
HttpOnly防止 JavaScript 读取
Secure仅通过 HTTPS 传输
SameSite=Lax防止 CSRF
Domain限制 Cookie 域名
Path限制 Cookie 路径
Max-Age设置过期时间

16.8 业务场景:电商网站安全配置

# 完整的电商网站安全配置
server {
    listen 443 ssl http2;
    server_name shop.example.com;
    
    # TLS 1.2 + 1.3
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    
    # HSTS(预加载)
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    
    # CSP(严格)
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' https://cdn.shop.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; connect-src 'self' https://api.shop.com wss://ws.shop.com" always;
    
    # 防止点击劫持
    add_header X-Frame-Options "DENY" always;
    
    # 防止 MIME 嗅探
    add_header X-Content-Type-Options "nosniff" always;
    
    # Referrer 策略
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    
    # 功能权限
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=(self)" always;
    
    # 支付页面特别配置
    location /checkout {
        # 更严格的 CSP
        add_header Content-Security-Policy "default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'; form-action 'self'; frame-ancestors 'none'" always;
    }
}

⚠️ 注意事项

  1. 始终使用 HTTPS:Let’s Encrypt 免费证书,没有理由不用
  2. HSTS 慎用 preload:一旦加入预加载列表,移除非常困难
  3. CSP 测试先行:先用 Report-Only 模式测试,确认无问题再执行
  4. TLS 1.0/1.1 已废弃:确保服务器禁用旧版本 TLS
  5. 定期更新证书:设置自动续期,防止证书过期
  6. 安全头部顺序:确保在所有响应中添加安全头部

🔗 扩展阅读


下一章第 17 章:调试与测试工具 — curl、Wireshark、httpie、浏览器 DevTools