HTTP 协议详解教程 / 第 16 章:HTTP 安全
第 16 章:HTTP 安全
安全是 Web 应用的生命线。本章全面介绍 HTTPS/TLS、各种安全头部以及常见攻击的防御手段。
16.1 HTTPS 与 TLS
为什么需要 HTTPS
| 威胁 | HTTP | HTTPS |
|---|
| 窃听 | ✗ 明文传输 | ✓ 加密传输 |
| 篡改 | ✗ 可被修改 | ✓ 完整性校验 |
| 冒充 | ✗ 无法验证身份 | ✓ 证书验证 |
TLS 握手流程(TLS 1.3)
客户端 服务器
│ │
│── ClientHello ──────────────────→│
│ 支持的密码套件、密钥共享 │
│ │
│←── ServerHello + Certificate ────│
│ 选定密码套件、证书、密钥共享 │
│ │
│── Finished ─────────────────────→│
│ 密钥确认 │
│ │
│←══ 加密通信 ════════════════════│
TLS 1.2 vs TLS 1.3
| 特性 | TLS 1.2 | TLS 1.3 |
|---|
| 握手延迟 | 2 RTT | 1 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-src | JavaScript | 'self' 'nonce-xxx' |
style-src | CSS | 'self' 'unsafe-inline' |
img-src | 图片 | 'self' data: https: |
connect-src | AJAX/WebSocket | 'self' https://api.* |
frame-src | iframe | '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 | 防止点击劫持 | DENY 或 SAMEORIGIN |
| X-XSS-Protection | XSS 过滤器 | 1; mode=block |
| Referrer-Policy | 控制 Referer | strict-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 剥离 | 强制降级到 HTTP | HSTS |
| 证书伪造 | 使用伪造证书 | 证书固定(Certificate Pinning) |
| DNS 劫持 | DNS 返回错误 IP | DNSSEC / DoH |
| ARP 欺骗 | 局域网 ARP 表污染 | HTTPS |
Certificate Transparency
# 证书透明度日志
# 所有公开信任的证书都必须记录到 CT 日志
# 浏览器验证 SCT(Signed Certificate Timestamp)
Expect-CT: max-age=86400, enforce, report-uri="/ct-report"
16.7 Cookie 安全
# 安全的 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;
}
}
⚠️ 注意事项
- 始终使用 HTTPS:Let’s Encrypt 免费证书,没有理由不用
- HSTS 慎用 preload:一旦加入预加载列表,移除非常困难
- CSP 测试先行:先用 Report-Only 模式测试,确认无问题再执行
- TLS 1.0/1.1 已废弃:确保服务器禁用旧版本 TLS
- 定期更新证书:设置自动续期,防止证书过期
- 安全头部顺序:确保在所有响应中添加安全头部
🔗 扩展阅读
下一章:第 17 章:调试与测试工具 — curl、Wireshark、httpie、浏览器 DevTools