HTTPS 与 SSL/TLS 原理详解:从证书到配置实战
HTTPS 是现代网站的标配。本文深入讲解 SSL/TLS 的工作原理、证书类型、Let's Encrypt 自动续期,以及 Nginx 的完整 HTTPS 配置。
为什么需要 HTTPS
HTTP 是明文传输。在同一个 Wi-Fi 下(比如咖啡馆),别人用 Wireshark 抓个包,你发的请求、Cookie、密码全看得见。
HTTPS 就是在 HTTP 外面套了一层 TLS(以前叫 SSL),把传输内容加密了。
但大多数人配 HTTPS 都是照着教程复制粘贴,出了问题不知道怎么排查。下面把这些讲清楚。
SSL 与 TLS 的关系
SSL 是老名字,3.0 版本之后改名为 TLS。
| 协议 | 状态 |
|------|------|
| SSL 2.0 / 3.0 | 已废弃,有安全漏洞 |
| TLS 1.0 / 1.1 | 已废弃 |
| TLS 1.2 | 目前主流 |
| TLS 1.3 | 新标准,更快更安全 |
**结论**:配 Nginx 时只开 TLS 1.2 和 1.3,1.0/1.1 全部关掉。
证书是怎么工作的
核心就三步:
2. **客户端**(浏览器)用内置的**根证书**验证服务器证书是否可信
3. 验证通过后,双方协商出一个**会话密钥**,后续通信用这个对称密钥加密
为什么不用非对称加密全程加密?因为慢。TLS 的设计是:**用非对称加密协商密钥,用对称加密传输数据**——各取所长。
证书类型
| 类型 | 验证内容 | 适合场景 |
|------|---------|--------|
| DV(Domain Validation) | 只验证域名所有权 | 个人项目、博客 |
| OV(Organization Validation) | 验证企业身份 | 企业官网 |
| EV(Extended Validation) | 严格验证企业身份 | 银行、金融(现在 EV 的绿色地址栏已取消,意义不大) |
| 通配符(Wildcard) | 支持 *.example.com | 多个子域名 |
个人项目用 Let's Encrypt 的 DV 证书就够了,免费,三个月自动续期。
Let's Encrypt 自动续期
用 certbot(Nginx 为例)
# 安装 certbot
sudo apt install certbot python3-certbot-nginx # Ubuntu/Debian
sudo yum install certbot python3-certbot-nginx # CentOS
# 自动配置 Nginx
sudo certbot --nginx -d example.com -d www.example.com
# 手动模式(如果 certbot 自动配置有问题)
sudo certbot certonly --nginx -d example.com
自动续期
certbot 安装时会自动加入 cron(在 /etc/cron.d/certbot),每天检查证书是否快过期(小于 30 天),自动续期。
手动测试续期是否正常:
sudo certbot renew --dry-run
如果 --dry-run 不报错,说明自动续期配置正常。
常见坑:端口 80 必须开放
Let's Encrypt 的 HTTP-01 验证方式需要访问你服务器的 80 端口。如果防火墙把 80 关了,续期会失败。
# 检查 certbot 续期是否成功(看日志)
sudo journalctl -u certbot.service --since "7 days ago"
Nginx 配置 HTTPS
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# 证书路径(certbot 默认路径)
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# TLS 版本(禁用 1.0/1.1)
ssl_protocols TLSv1.2 TLSv1.3;
# 加密套件(推荐 Mozilla 的配置)
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256";
ssl_prefer_server_ciphers off;
# HSTS(强制浏览器用 HTTPS 访问,防中间人降级攻击)
add_header Strict-Transport-Security "max-age=63072000" always;
# 根路径
root /var/www/html;
index index.html;
}
# HTTP 自动跳转 HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
如何排查证书问题
用 openssl 查看证书信息
openssl s_client -connect example.com:443 -servername example.com | openssl x509 -noout -text
重点看:
用 curl 验证
curl -vI https://example.com
如果证书有问题,curl 会报 SSL certificate problem。
浏览器显示"不安全"的常见原因
2. 证书不包含当前访问的域名(比如证书只签了 example.com,用户访问 www.example.com)
3. 混合内容(页面是 HTTPS,但里面引用了 HTTP 的资源)——这个在 DevTools 的 Console 里能看到警告
4. 用了自签名证书(浏览器不信任)
中间人攻击(MITM)是怎么回事
攻击者把你和目标服务器之间的流量拦截,假装自己是服务器(对你)和客户端(对服务器)。
HTTPS 防 MITM 的核心就是**证书验证**——如果攻击者没有目标域名的私钥,他就没法签发合法的证书,浏览器会报证书不安全。
但有一种情况例外:**用户主动信任了攻击者的根证书**(比如公司内网的安全审计、或者手机装了恶意证书)。一旦根证书被信任,MITM 就完全可行了。
所以:不要随便装来历不明的根证书。
HSTS
HSTS(HTTP Strict Transport Security)是让浏览器记住"这个域名只能用 HTTPS 访问"。
加了 HSTS 之后,即使用户手动把地址栏的 https:// 改成 http://,浏览器也会强制用 HTTPS。
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
max-age 单位是秒,63072000 是两年。includeSubDomains 表示子域名也适用。
**注意**:开启 HSTS 之前,确保你的网站 HTTPS 是稳定可用的——一旦浏览器记住了 HSTS,HTTP 就再也访问不了了。
总结
HTTPS 不是可选项,是基线。Let's Encrypt + certbot 基本是标配了,配置一次自动续期,后面不用管。
> **Pro Tip**: 用 SSL Labs Test(https://www.ssllabs.com/ssltest/)可以给你网站的 HTTPS 配置打分,A+ 是满分。