Chapter 08

安全配置与加密

正确的 TLS 配置、加密算法选择、密钥管理——安全的基础设施保障

常见安全配置错误

典型配置风险

默认密码
路由器/摄像头/数据库使用出厂默认凭据(admin/admin、root/root)。Mirai 僵尸网络 2016 年感染 50 万台 IoT 设备,全部因使用默认密码。任何系统上线前必须更改所有默认凭据。
调试模式开启
生产环境开启 DEBUG=True(Flask/Django),会暴露完整堆栈跟踪、源代码、配置变量,甚至允许在浏览器中直接执行代码。使用环境变量区分开发和生产配置,生产环境务必关闭调试模式。
目录列表
Nginx/Apache 开启目录浏览(autoindex on),攻击者可以枚举服务器文件,发现备份文件(.bak)、配置文件(.env)、源码压缩包。务必禁用,只暴露必要的 URL 路径。
详细错误信息
生产环境返回数据库错误详情(表名、字段名、SQL 语句),帮助攻击者了解系统架构。生产环境应返回通用错误消息,错误详情只记录到内部日志。
云存储公开访问
AWS S3 / GCS Bucket 设置为公开可读,是近年数据泄露的重灾区。默认配置应为私有,使用 Pre-signed URL 临时授权访问,定期审计存储桶权限。

HTTPS 与 TLS 最佳配置

# Nginx TLS 安全配置(2024 年推荐)
server {
    listen 443 ssl http2;
    server_name example.com;

    ssl_certificate     /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;

    # 只允许 TLS 1.2 和 1.3,禁用不安全的 TLS 1.0/1.1/SSL
    ssl_protocols TLSv1.2 TLSv1.3;

    # 强加密套件(前向保密 ECDHE,认证加密 GCM)
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;

    # HSTS:365 天强制 HTTPS
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # Session 缓存与前向保密
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;
    ssl_session_tickets off;  # 禁用 Session Tickets 保证前向保密

    # OCSP Stapling(加速证书验证)
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 valid=300s;
}

敏感数据加密

传输中加密(In-Transit)

传输中的数据通过 TLS 加密,上面 Nginx 配置已覆盖。额外注意:

静态加密(At-Rest)

from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

# AES-256-GCM:认证加密(同时保证保密性和完整性)
# 密钥长度:256 位 = 32 字节

class EncryptionService:
    def __init__(self, key: bytes):
        assert len(key) == 32, "AES-256 密钥必须是 32 字节"
        self.aesgcm = AESGCM(key)

    def encrypt(self, plaintext: str) -> bytes:
        nonce = os.urandom(12)  # GCM 标准 nonce 为 12 字节,每次必须随机!
        ciphertext = self.aesgcm.encrypt(nonce, plaintext.encode(), None)
        return nonce + ciphertext  # 将 nonce 与密文一起存储(nonce 不需要保密)

    def decrypt(self, data: bytes) -> str:
        nonce, ciphertext = data[:12], data[12:]
        plaintext = self.aesgcm.decrypt(nonce, ciphertext, None)
        # 如果数据被篡改,decrypt 会抛出 InvalidTag 异常(认证失败)
        return plaintext.decode()

# 使用示例(密钥从环境变量获取,见下文密钥管理)
import base64
key = base64.b64decode(os.environ['ENCRYPTION_KEY'])
enc = EncryptionService(key)

encrypted = enc.encrypt("用户的银行卡号")
original = enc.decrypt(encrypted)  # "用户的银行卡号"

密钥管理:永远不要硬编码 Secret

最危险的错误:代码中的密钥

# 极度危险!Secret 硬编码在代码中
DATABASE_URL = "postgresql://user:mypassword123@db.example.com/prod"
SECRET_KEY = "my-super-secret-jwt-key"
AWS_SECRET = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"

# 这些 Secret 一旦提交到 Git,即使后来删除,仍然在 Git 历史中
# GitHub 的 Secret Scanning 会自动检测并通知安全团队

# 正确:使用环境变量
import os
DATABASE_URL = os.environ['DATABASE_URL']
SECRET_KEY = os.environ['SECRET_KEY']

环境变量管理(.env 文件)

# .env 文件(本地开发,永远不提交到 Git!)
DATABASE_URL=postgresql://user:pass@localhost/mydb
SECRET_KEY=dev_only_secret_key
REDIS_URL=redis://localhost:6379

# .gitignore 中必须包含:
.env
.env.local
.env.production
*.pem
*_rsa
*_rsa.pub
# 检查是否有 Secret 被意外提交到 Git 历史
# 使用 trufflehog 扫描 Git 历史
docker run --rm -it trufflesecurity/trufflehog:latest \
  git file:///path/to/repo --only-verified

# 如果发现 Secret 被提交:
# 1. 立即轮换(更换)该 Secret(假设已被泄露)
# 2. 在 git 历史中删除(git filter-branch 或 BFG Repo-Cleaner)
# 3. 强制推送(需要通知团队成员)

生产环境密钥管理

HashiCorp Vault
开源的专用 Secret 管理工具。支持动态 Secret(每次请求生成临时数据库凭据,用后即失效)、加密即服务(应用不需要处理密钥,直接调用 Vault 加密 API)、审计日志(记录所有 Secret 访问)。
AWS Secrets Manager
AWS 托管的 Secret 存储服务。自动轮换数据库密码(支持 RDS)、KMS 加密、IAM 精细访问控制。成本:约 $0.40/Secret/月。适合已在 AWS 上的应用。
Kubernetes Secrets
K8s 原生 Secret 资源,以 Base64 编码(非加密!)存储。必须配合 etcd 加密(Encryption at Rest)和 RBAC 限制访问。更好的方案:使用 External Secrets Operator 对接 Vault/AWS SM。
GitHub Actions Secrets
在仓库 Settings → Secrets 中配置,CI/CD 流水线通过 ${{ secrets.MY_SECRET }} 引用。Secret 在日志中自动脱敏,Fork PR 中不可访问(防止 PR 注入攻击)。

安全 HTTP Headers 完整配置清单

安全 HTTP 响应头是浏览器安全的重要防线,告诉浏览器如何安全地处理页面内容。

# Nginx:完整的安全 Headers 配置

# 防止 XSS(限制脚本来源)
add_header Content-Security-Policy
  "default-src 'self'; script-src 'self' 'nonce-{nonce}'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'" always;

# 防止点击劫持(禁止在 iframe 中嵌入)
add_header X-Frame-Options "DENY" always;

# 防止 MIME 类型嗅探
add_header X-Content-Type-Options "nosniff" always;

# 控制 Referer 信息泄露
add_header Referrer-Policy "strict-origin-when-cross-origin" always;

# 禁用浏览器某些危险特性(权限策略)
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;

# 强制 HTTPS(已在上文配置)
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

# 跨域隔离(启用高精度计时器等特性,需配合 COOP/COEP)
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;

# 隐藏服务器版本信息
server_tokens off;
Header作用推荐值
Content-Security-Policy 防 XSS,限制资源加载来源 按需配置,至少设 default-src 和 object-src
X-Frame-Options 防点击劫持,禁止 iframe 嵌入 DENYSAMEORIGIN
X-Content-Type-Options 禁止浏览器猜测 MIME 类型 nosniff
Strict-Transport-Security 强制 HTTPS,防止降级攻击 max-age=31536000; includeSubDomains
Referrer-Policy 控制 Referer 头信息泄露 strict-origin-when-cross-origin
Permissions-Policy 禁用不需要的浏览器 API 禁用摄像头/麦克风/地理位置(若不需要)
快速检测你的网站安全 Headers

在线工具 securityheaders.com 可以快速检测任意网站的安全 Headers 配置情况,并给出评分(A+ 到 F)和改进建议。Mozilla Observatory(observatory.mozilla.org)提供更全面的安全评估,包括 TLS 配置、Cookie 安全等。

本章小结

安全配置是"防守最后一公里":① 生产环境关闭调试模式、默认账号,最小化暴露面;② TLS 使用 1.2+,配置前向保密加密套件,启用 HSTS;③ 敏感数据用 AES-256-GCM 加密存储,密钥从 Vault/KMS 获取,永远不硬编码在代码或版本库中;④ 完整配置安全 HTTP Headers(CSP、HSTS、X-Frame-Options 等),几行配置就能阻挡多种客户端攻击。安全配置不需要额外编写代码,却能以最低成本提供显著的安全保障。