{T}

SSL 安全协议

SSL/TLS 通过分层设计混合加密体系完备的握手协议,在 TCP 之上构建了一个安全通道:

  1. 加密层次:记录层加密 + 握手层协商
  2. 密码学基础:非对称加密(身份认证+密钥交换)+ 对称加密(数据加密)
  3. 前向安全:基于临时的会话密钥
  4. 性能优化:会话复用、False Start、TLS 1.3
  5. 演进方向:更快的握手、更强的安全、更好的隐私保护

SSL/TLS 位于应用层和传输层之间,对上层应用透明,应用协议无需修改。为 TCP 提供端到端的加密通道

code
┌─────────────────────────────────────────────────┐
│                   应用层                         │
│  HTTP, FTP, SMTP, IMAP, DNS over TLS, etc.      │
├─────────────────────────────────────────────────┤
│                    SSL/TLS                       │ ← 安全层
├─────────────────────────────────────────────────┤
│                    TCP                          │
├─────────────────────────────────────────────────┤
│                    IP                           │
├─────────────────────────────────────────────────┤
│                   链路层                         │
└─────────────────────────────────────────────────┘

SSL/TLS 核心安全目标

机密性(Confidentiality)

完整性(Integrity)

  • 防篡改:通过**消息认证码(MAC)**确保数据完整
  • 防重放:通过序列号防止重放攻击

身份认证(Authentication)

  • 服务器身份验证(必选)
  • 客户端身份验证(可选)
  • 双向认证(mTLS)
图表渲染中…
图表渲染中…

密码学原理解析

1. 非对称加密(密钥交换)

python
# RSA 密钥交换原理
# 客户端生成预主密钥,用服务器公钥加密
pre_master_secret = generate_random(48)
encrypted_pre_master = RSA_encrypt(
    server_public_key,
    pre_master_secret
)

# 服务器用私钥解密
pre_master_secret = RSA_decrypt(
    server_private_key,
    encrypted_pre_master
)

2. 对称加密(数据加密)

code
应用数据加密流程:
1. 主密钥 → 生成6个密钥
   - 客户端写MAC密钥
   - 服务器写MAC密钥
   - 客户端写加密密钥
   - 服务器写加密密钥
   - 客户端写IV
   - 服务器写IV

2. 数据加密 = 加密算法(对称密钥, 应用数据 + MAC)

3. Diffie-Hellman 密钥交换

python
# DH 密钥交换数学原理
# 公共参数: 大素数p, 生成元g

# 客户端
client_private_key = random_int(1, p-1)
client_public_key = (g^client_private_key) mod p

# 服务器
server_private_key = random_int(1, p-1)
server_public_key = (g^server_private_key) mod p

# 交换公钥后,双方计算共享密钥
client_shared_secret = (server_public_key^client_private_key) mod p
server_shared_secret = (client_public_key^server_private_key) mod p
# client_shared_secret == server_shared_secret

记录层协议(Record Protocol)

数据封装格式:

code
┌─────────────────────────────────────────┐
│     TLS Record Layer (应用数据)          │
├──────────┬──────────┬────────┬─────────┤
│ 类型     │ 版本     │ 长度   │ 数据     │
│ 1字节    │ 2字节    │ 2字节  │ 长度可变 │
├──────────┼──────────┼────────┼─────────┤
│ 0x16     │ 0x0303   │ 0x00A0 │ ...     │ ← 握手记录
│ 0x17     │ 0x0303   │ 0x1000 │ ...     │ ← 应用数据记录
│ 0x15     │ 0x0303   │ 0x0002 │ ...     │ ← 警报记录
└──────────┴──────────┴────────┴─────────┘

数据分片与加密:

图表渲染中…

SSL/TLS 的 Nginx 安全配置示例

nginx
server {
    listen 443 ssl http2;

    # 证书配置
    ssl_certificate /etc/ssl/certs/example.com.crt;
    ssl_certificate_key /etc/ssl/private/example.com.key;

    # 协议版本
    ssl_protocols TLSv1.2 TLSv1.3;

    # 密码套件(TLS 1.2+1.3)
    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 on;

    # 前向安全
    ssl_ecdh_curve X25519:secp384r1;

    # 会话复用
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    ssl_session_tickets on;

    # 安全头部
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_trusted_certificate /etc/ssl/certs/ca-bundle.crt;
}

python2-certbot-nginx 自动配置 SSL

Certbot 是个免费、开源的工具,用于自动化在网站上启用和管理 HTTPS 证书的过程,由 Electronic Frontier Foundation (EFF) 开发。python2-certbot-nginx 是 Certbot 的 Nginx 插件,可以自动配置 Nginx 并管理 SSL 证书

nginx
server {
  server_name nginx.zhangzhengyang.com
  listen 9099
   
    location / {
        alias /var/www/html/index.html;
  }  
}

在 CentOS 7.9 上安装 Certbot

bash
# 安装 EPEL 仓库
sudo yum install -y epel-release

# 安装 Certbot 和 Nginx 插件
sudo yum install -y certbot python2-certbot-nginx

# 验证安装
certbot --version

获取和管理证书

自动获取和配置证书

bash
# 自动获取证书并配置 Nginx,如果要选择,可以选择 1
sudo certbot --nginx -d example.com -d www.example.com

# 交互式模式
sudo certbot --nginx

# 保存配置时选择重定向 HTTP 到 HTTPS

可以指定 nginx 配置文件的目录:

  • --nginx-server-root:指定 Nginx 主配置目录(通常是 /etc/nginx)
  • --nginx-vhost-root:指定虚拟主机配置文件目录(通常是 /etc/nginx/sites-available)
bash
sudo certbot --nginx \
  --nginx-server-root /etc/nginx \
  --nginx-vhost-root /etc/nginx/sites-available \
  -d example.com \
  -d www.example.com

证书续期

手动续期

bash
# 测试续期(不会实际续期)
sudo certbot renew --dry-run

# 手动续期所有证书
sudo certbot renew

# 续期特定证书
sudo certbot renew --cert-name example.com

自动续期

bash
# 创建 cron 任务
echo "0 0,12 * * * root /usr/bin/certbot renew --quiet" | sudo tee /etc/cron.d/certbot-renew

# 或者使用 systemd timer
sudo systemctl enable certbot-renew.timer
sudo systemctl start certbot-renew.timer

Certbot 生成的 Nginx 配置示例

当使用 certbot --nginx 命令时,Certbot 会自动修改 Nginx 配置,添加以下内容:

nginx
server {
    server_name example.com www.example.com;
    root /var/www/example.com;
    index index.html;

    # 以下是 Certbot 添加的内容

    # HTTPS 重定向配置
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

    # HTTP 到 HTTPS 重定向
    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot
}

server {
    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

    listen 80;
    server_name example.com www.example.com;
    return 404; # managed by Certbot
}

SSL 参数配置

Certbot 使用 /etc/letsencrypt/options-ssl-nginx.conf 文件来配置 SSL 参数。这个文件的内容通常如下:

nginx
# SSL 协议版本
ssl_protocols TLSv1.2 TLSv1.3;

# 密码套件
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-S384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;

# 会话缓存
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;

# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;

# 前向安全
ssl_ecdh_curve X25519:secp256k1:secp384r1;

# 安全头部
resolver 8.8.8.8 8.8.4.4;

证书文件位置

Let's Encrypt 证书通常存储在以下位置:

bash
# 证书目录结构
/etc/letsencrypt/live/example.com/
├── cert.pem       # 服务器证书
├── chain.pem      # 中间证书
├── fullchain.pem  # 证书链(cert.pem + chain.pem)
└── privkey.pem    # 私钥

# 实际文件存储在 archive 目录,live 目录中有符号链接
/etc/letsencrypt/archive/example.com/

常用 Certbot 命令

bash
# 列出所有证书
sudo certbot certificates

# 删除证书
sudo certbot delete --cert-name example.com

# 撤销证书
sudo certbot revoke --cert-path /etc/letsencrypt/live/example.com/cert.pem

# 设置默认续期选项
sudo certbot register --email admin@example.com --agree-tos --no-eff-email

# 测试 Nginx 配置
sudo certbot --nginx --dry-run -d example.com

# 指定不同的证书存储目录
sudo certbot --nginx --config-dir /opt/certbot -d example.com

高级配置

使用 DNS 验证(通配符证书)

bash
# 安装 DNS 插件(以 Cloudflare 为例)
sudo yum install -y python2-certbot-dns-cloudflare

# 创建 Cloudflare API 凭据文件
sudo mkdir -p /etc/letsencrypt
sudo tee /etc/letsencrypt/cloudflare.ini << 'EOF'
dns_cloudflare_api_token = your_api_token_here
EOF
sudo chmod 600 /etc/letsencrypt/cloudflare.ini

# 获取通配符证书
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
  -d example.com -d "*.example.com"

自定义 SSL 参数

bash
# 编辑 Certbot 的 SSL 参数文件
sudo nano /etc/letsencrypt/options-ssl-nginx.conf

# 添加自定义参数
ssl_dhparam /etc/letsencrypt/dhparams.pem;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;

多域名证书

bash
# 为多个域名获取单个证书
sudo certbot --nginx -d example.com -d www.example.com -d blog.example.com -d shop.example.com

故障排除

证书获取失败

bash
# 检查 DNS 解析
dig +short example.com

# 检查防火墙设置
sudo firewall-cmd --list-all

# 检查端口 80 是否开放
sudo netstat -tlnp | grep :80

# 暂时停止 Nginx 并尝试获取证书
sudo systemctl stop nginx
sudo certbot certonly --standalone -d example.com
sudo systemctl start nginx

Nginx 配置错误

bash
# 测试 Nginx 配置
sudo nginx -t

# 检查 Nginx 日志
sudo tail -f /var/log/nginx/error.log

# 恢复备份的 Nginx 配置
sudo cp /etc/nginx/nginx.conf.backup /etc/nginx/nginx.conf
sudo nginx -s reload

证书续期失败

bash
# 查看续期日志
sudo journalctl -u certbot
sudo cat /var/log/letsencrypt/letsencrypt.log

# 强制续期
sudo certbot renew --force-renewal

# 重新获取证书
sudo certbot delete --cert-name example.com
sudo certbot --nginx -d example.com

与现有 Nginx 配置集成

如果你已有 Nginx 配置,可以这样集成 Certbot:

bash
# 1. 备份现有配置
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.backup
sudo cp -r /etc/nginx/conf.d /etc/nginx/conf.d.backup

# 2. 获取证书(不修改配置)
sudo certbot certonly --nginx -d example.com

# 3. 手动修改 Nginx 配置
sudo nano /etc/nginx/conf.d/example.conf

# 4. 添加 SSL 配置
server {
    listen 80;
    server_name example.com;
    
    # 重定向到 HTTPS
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;
    root /var/www/example.com;
    index index.html;
    
    # SSL 配置
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
    
    # 其他配置...
}

自动化部署脚本

创建自动化部署脚本 deploy-ssl.sh

bash
#!/bin/bash
# 自动 SSL 部署脚本

DOMAIN=$1
EMAIL=$2
WEBROOT="/var/www/${DOMAIN}"

# 检查参数
if [ -z "$DOMAIN" ] || [ -z "$EMAIL" ]; then
    echo "用法: $0 域名 邮箱"
    exit 1
fi

# 创建网站目录
sudo mkdir -p $WEBROOT
sudo chown -R nginx:nginx $WEBROOT
sudo chmod -R 755 $WEBROOT

# 创建默认页面
echo "<html><body><h1>It works!</h1><p>SSL 自动配置成功</p></body></html>" | sudo tee $WEBROOT/index.html

# 获取证书
echo "获取 SSL 证书..."
sudo certbot --nginx -d $DOMAIN -d www.$DOMAIN --email $EMAIL --agree-tos --no-eff-email --redirect

# 设置自动续期
echo "0 0,12 * * * root /usr/bin/certbot renew --quiet" | sudo tee /etc/cron.d/certbot-renew

echo "SSL 配置完成!"
echo "网站: https://$DOMAIN"
echo "证书位置: /etc/letsencrypt/live/$DOMAIN/"

使用脚本:

bash
chmod +x deploy-ssl.sh
sudo ./deploy-ssl.sh example.com admin@example.com