本文最后更新于72 天前,其中的信息可能已经过时,如有错误请发送邮件到583126841@qq.com
什么是 HTTPS
HTTPS(HyperText Transfer Protocol Secure)是 HTTP 的安全版本。它在 HTTP 和 TCP 之间添加了 SSL/TLS 加密层,提供数据加密、身份验证和数据完整性保护。
HTTP: 应用层(HTTP) -> 传输层(TCP) -> 网络层(IP)
HTTPS: 应用层(HTTP) -> 安全层(SSL/TLS) -> 传输层(TCP) -> 网络层(IP)
HTTP 的安全问题
1. 窃听风险
HTTP 以明文传输数据,任何人都可以截获和查看:
客户端 ----[明文数据]----> 服务器
↑
攻击者可以看到所有内容
风险:
- 密码被窃取
- 个人信息泄露
- 会话劫持
2. 篡改风险
数据在传输过程中可能被修改:
客户端 ----[数据]----> 攻击者 ----[修改后的数据]----> 服务器
风险:
- 注入恶意代码
- 修改交易金额
- 重定向到钓鱼网站
3. 冒充风险
无法验证服务器的身份:
客户端 ----[请求]----> 假冒服务器
风险:
- 钓鱼网站
- 中间人攻击
- 数据被发送到错误的服务器
HTTPS 如何解决这些问题
1. 加密(Encryption)
使用对称加密和非对称加密保护数据:
- 对称加密:加密和解密使用相同的密钥(如 AES)
- 非对称加密:使用公钥加密,私钥解密(如 RSA)
2. 身份验证(Authentication)
使用数字证书验证服务器身份:
- 证书由可信的证书颁发机构(CA)签发
- 浏览器验证证书的有效性
- 确保连接到正确的服务器
3. 完整性(Integrity)
使用消息摘要算法(如 SHA-256)确保数据未被篡改:
- 计算数据的哈希值
- 接收方验证哈希值
- 任何修改都会被检测到
SSL/TLS 协议
SSL vs TLS
- SSL(Secure Sockets Layer):早期的安全协议
- SSL 2.0(已废弃)
- SSL 3.0(已废弃,存在安全漏洞)
- TLS(Transport Layer Security):SSL 的继任者
- TLS 1.0(2006年,已过时)
- TLS 1.1(2008年,已过时)
- TLS 1.2(2008年,广泛使用)
- TLS 1.3(2018年,最新版本,推荐使用)
现在通常说的 SSL 实际上指的是 TLS。
TLS 握手过程
TLS 握手建立安全连接:
sequenceDiagram
participant Client as 客户端
participant Server as 服务器
%% ClientHello
Client->>Server: 1. ClientHello<br/>(支持的加密套件、TLS版本)
%% ServerHello
Server->>Client: 2. ServerHello<br/>(选择的加密套件、TLS版本)
%% Certificate
Server->>Client: 3. Certificate<br/>(服务器证书)
%% ServerKeyExchange
Server->>Client: 4. ServerKeyExchange<br/>(服务器公钥)
%% ServerHelloDone
Server->>Client: 5. ServerHelloDone
%% ClientKeyExchange
Client->>Server: 6. ClientKeyExchange<br/>(预主密钥,用服务器公钥加密)
%% ChangeCipherSpec
Client->>Server: 7. ChangeCipherSpec<br/>(切换到加密通信)
%% Finished
Client->>Server: 8. Finished<br/>(握手完成)
%% Server ChangeCipherSpec
Server->>Client: 9. ChangeCipherSpec
%% Server Finished
Server->>Client: 10. Finished
%% Encrypted Data
Note over Client,Server: 开始加密通信
Client<<->>Server: 加密的应用数据
简化流程:
- 客户端问候:客户端发送支持的加密算法列表
- 服务器问候:服务器选择加密算法并发送证书
- 密钥交换:双方协商会话密钥
- 开始加密通信:使用会话密钥加密数据
TLS 1.3 的改进
TLS 1.3 简化了握手过程,提高了性能和安全性:
- 减少握手往返次数(1-RTT)
- 支持 0-RTT(零往返时间)恢复
- 移除不安全的加密算法
- 强制使用前向保密(Forward Secrecy)
数字证书
证书的作用
数字证书用于验证服务器的身份,包含:
- 域名
- 组织信息
- 公钥
- 证书颁发机构(CA)
- 有效期
- 数字签名
证书类型
1. DV 证书(Domain Validation)
- 只验证域名所有权
- 签发速度快(几分钟到几小时)
- 价格便宜或免费(如 Let’s Encrypt)
- 适合个人网站、博客
2. OV 证书(Organization Validation)
- 验证域名和组织身份
- 签发需要几天
- 价格中等
- 适合企业网站
3. EV 证书(Extended Validation)
- 严格验证组织身份
- 签发需要一周或更长
- 价格较高
- 浏览器地址栏显示组织名称
- 适合金融、电商等高安全要求的网站
证书链
证书通常形成一个信任链:
根证书(Root CA)
↓
中间证书(Intermediate CA)
↓
服务器证书(End-entity Certificate)
- 根证书:预装在操作系统或浏览器中
- 中间证书:由根 CA 签发,用于签发服务器证书
- 服务器证书:网站使用的证书
证书验证过程
浏览器验证证书的步骤:
- 检查证书是否过期
- 检查域名是否匹配
- 验证证书签名
- 检查证书是否被吊销(CRL 或 OCSP)
- 验证证书链到受信任的根 CA
HTTPS 的端口
- HTTP 默认端口:80
- HTTPS 默认端口:443
HTTPS 的性能影响
性能开销
- TLS 握手:增加延迟(1-2 个往返)
- 加密/解密:消耗 CPU 资源
- 证书验证:需要额外的处理
性能优化
- 使用 TLS 1.3:减少握手时间
- 启用 HTTP/2:多路复用,减少连接数
- 会话恢复:重用之前的会话密钥
- OCSP Stapling:减少证书验证时间
- 硬件加速:使用专用硬件加速加密
- CDN:使用内容分发网络
配置 HTTPS
获取证书
免费证书:Let’s Encrypt
# 安装 Certbot
sudo apt-get install certbot
# 获取证书
sudo certbot certonly --standalone -d example.com
# 自动续期
sudo certbot renew
自签名证书(仅用于测试)
# 生成私钥
openssl genrsa -out server.key 2048
# 生成证书签名请求
openssl req -new -key server.key -out server.csr
# 生成自签名证书
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
Nginx 配置
server {
listen 443 ssl http2;
server_name example.com;
# 证书文件
ssl_certificate /path/to/certificate.crt;
ssl_certificate_key /path/to/private.key;
# SSL 协议版本
ssl_protocols TLSv1.2 TLSv1.3;
# 加密套件
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
# 会话缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
location / {
root /var/www/html;
index index.html;
}
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
Apache 配置
<VirtualHost *:443>
ServerName example.com
DocumentRoot /var/www/html
SSLEngine on
SSLCertificateFile /path/to/certificate.crt
SSLCertificateKeyFile /path/to/private.key
SSLCertificateChainFile /path/to/chain.crt
# SSL 协议
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite HIGH:!aNULL:!MD5
# HSTS
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
</VirtualHost>
# HTTP 重定向到 HTTPS
<VirtualHost *:80>
ServerName example.com
Redirect permanent / <https://example.com/>
</VirtualHost>
HTTPS 最佳实践
1. 使用强加密
- 使用 TLS 1.2 或 TLS 1.3
- 禁用 SSL 2.0、SSL 3.0、TLS 1.0、TLS 1.1
- 使用强加密套件
2. 启用 HSTS
强制浏览器使用 HTTPS:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
3. 使用完整的证书链
确保服务器发送完整的证书链,包括中间证书。
4. 定期更新证书
- 监控证书过期时间
- 设置自动续期
- 提前更新证书
5. 启用 OCSP Stapling
减少证书验证时间:
ssl_stapling on;
ssl_stapling_verify on;
6. 使用 HTTP/2
提高性能:
listen 443 ssl http2;
7. 重定向 HTTP 到 HTTPS
确保所有流量都使用 HTTPS:
return 301 https://$server_name$request_uri;
混合内容问题
HTTPS 页面中加载 HTTP 资源会导致混合内容警告:
<!-- 错误:HTTPS 页面加载 HTTP 资源 -->
<img src="<http://example.com/image.jpg>"><script src="<http://example.com/script.js>"></script><!-- 正确:使用 HTTPS -->
<img src="<https://example.com/image.jpg>"><script src="<https://example.com/script.js>"></script><!-- 或使用协议相对 URL -->
<img src="//example.com/image.jpg">
HTTPS 的局限性
- 不能防止所有攻击:
- 不能防止 XSS、CSRF 等应用层攻击
- 不能防止服务器被入侵
- 证书可能被伪造:
- CA 被攻破
- 证书被盗
- 性能开销:
- 增加延迟
- 消耗 CPU
- 配置复杂:
- 需要正确配置
- 需要维护证书
检测 HTTPS 配置
在线工具
- SSL Labs:https://www.ssllabs.com/ssltest/
- Security Headers:https://securityheaders.com/
命令行工具
# 查看证书信息
openssl s_client -connect example.com:443 -showcerts
# 测试 TLS 版本
openssl s_client -connect example.com:443 -tls1_2
openssl s_client -connect example.com:443 -tls1_3
# 查看支持的加密套件
nmap --script ssl-enum-ciphers -p 443 example.com
HTTPS 的安全深度解析
1. HTTPS 如何防止中间人攻击
中间人攻击(MITM)的原理:
没有 HTTPS 的情况:
用户 <--HTTP--> 攻击者 <--HTTP--> 服务器
1. 用户发送:POST /login {username: "admin", password: "secret"}
2. 攻击者截获请求,看到明文密码
3. 攻击者可以修改请求内容
4. 攻击者转发(或不转发)到服务器
5. 攻击者截获响应,可以修改内容
6. 用户收到被篡改的响应
HTTPS 的保护机制:
有 HTTPS 的情况:
用户 <--加密--> 攻击者 <--加密--> 服务器
1. 用户请求建立 HTTPS 连接
2. 服务器发送数字证书
3. 用户验证证书(CA 签名、域名、有效期)
4. 如果攻击者伪造证书,浏览器会警告
5. 建立加密通道后,所有数据都被加密
6. 攻击者无法解密或篡改数据
详细的 TLS 握手过程:
1. Client Hello(客户端问候)
- 支持的 TLS 版本
- 支持的加密套件列表
- 随机数(Client Random)
2. Server Hello(服务器问候)
- 选择的 TLS 版本
- 选择的加密套件
- 随机数(Server Random)
- 数字证书
3. 证书验证
- 客户端验证证书链
- 检查证书是否被 CA 签名
- 检查域名是否匹配
- 检查证书是否过期
- 检查证书是否被吊销
4. 密钥交换
- 客户端生成 Pre-Master Secret
- 使用服务器公钥加密
- 发送给服务器
5. 生成会话密钥
- 双方使用 Client Random + Server Random + Pre-Master Secret
- 生成对称加密密钥(Session Key)
6. 开始加密通信
- 使用 Session Key 加密所有数据
- 提供机密性和完整性保护
2. 数字证书的作用和验证
为什么需要证书颁发机构(CA)
问题场景:没有 CA 的情况
攻击者的中间人攻击:
1. 用户请求访问 bank.com
2. 攻击者拦截请求
3. 攻击者生成自己的证书,声称是 bank.com
4. 用户如何知道这个证书是真的?
5. 如果没有 CA,用户无法验证
6. 攻击成功
CA 的作用:
有 CA 的情况:
1. bank.com 向可信 CA 申请证书
2. CA 验证 bank.com 的身份
3. CA 使用自己的私钥签名证书
4. 用户浏览器内置了 CA 的公钥(根证书)
5. 用户访问 bank.com 时:
- 收到 bank.com 的证书
- 使用 CA 的公钥验证签名
- 如果签名有效,证明证书是 CA 颁发的
- 如果攻击者伪造证书,签名验证失败
6. 攻击失败
证书链验证:
证书链:根证书 → 中间证书 → 网站证书
示例:
1. 根 CA: DigiCert Global Root CA
- 浏览器内置,完全信任
2. 中间 CA: DigiCert SHA2 Secure Server CA
- 由根 CA 签名
3. 网站证书: bank.com
- 由中间 CA 签名
验证过程:
1. 验证 bank.com 证书是否由中间 CA 签名 ✓
2. 验证中间 CA 证书是否由根 CA 签名 ✓
3. 验证根 CA 是否在信任列表中 ✓
4. 所有验证通过,信任 bank.com 证书
证书验证的详细步骤
// 证书验证伪代码
function verifyCertificate(cert, hostname) {
// 1. 检查证书是否过期
if (cert.notBefore > Date.now() || cert.notAfter < Date.now()) {
return {valid: false, error: '证书已过期或尚未生效'};
}
// 2. 检查域名是否匹配
if (!cert.subjectAltNames.includes(hostname)) {
return {valid: false, error: '域名不匹配'};
}
// 3. 验证证书链
let currentCert = cert;
while (currentCert.issuer !== currentCert.subject) {
const issuerCert = findIssuerCertificate(currentCert.issuer);
if (!issuerCert) {
return {valid: false, error: '无法找到颁发者证书'};
}
// 验证签名
if (!verifySignature(currentCert, issuerCert.publicKey)) {
return {valid: false, error: '证书签名无效'};
}
currentCert = issuerCert;
}
// 4. 检查根证书是否在信任列表中
if (!trustedRootCAs.includes(currentCert)) {
return {valid: false, error: '根证书不受信任'};
}
// 5. 检查证书是否被吊销(OCSP 或 CRL)
if (isCertificateRevoked(cert)) {
return {valid: false, error: '证书已被吊销'};
}
return {valid: true};
}
3. 常见的 HTTPS 攻击和防护
SSL 剥离攻击(SSL Stripping)
攻击原理:
1. 用户访问 <http://bank.com>(注意是 HTTP)
2. 攻击者拦截请求
3. 正常情况:服务器返回 302 重定向到 <https://bank.com>
4. 攻击者修改响应:不重定向,直接返回 HTTP 页面
5. 用户在 HTTP 页面上输入密码
6. 攻击者截获明文密码
7. 攻击者通过 HTTPS 连接到真实服务器
8. 用户以为正常登录,但密码已被窃取
防护措施:HSTS
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
工作原理:
1. 用户第一次通过 HTTPS 访问网站
2. 服务器返回 HSTS 头部
3. 浏览器记录:bank.com 必须使用 HTTPS
4. 后续访问:
- 用户输入 <http://bank.com>
- 浏览器自动转换为 <https://bank.com>
- 不发送 HTTP 请求
- 攻击者无法拦截
HSTS Preload:
问题:第一次访问仍可能使用 HTTP
解决方案:HSTS Preload List
1. 网站申请加入 HSTS Preload List
2. 浏览器内置这个列表
3. 用户第一次访问就使用 HTTPS
4. 完全避免 SSL 剥离攻击
申请地址:<https://hstspreload.org/>
证书伪造攻击
攻击场景:
1. 攻击者控制了一个 CA(或 CA 被入侵)
2. 攻击者为 bank.com 签发假证书
3. 攻击者进行中间人攻击
4. 用户收到假证书,但签名有效
5. 用户信任假证书
6. 攻击成功
防护措施:证书透明度(CT)
Certificate Transparency:
1. CA 签发证书时,必须提交到公开日志
2. 网站可以监控自己域名的证书
3. 如果发现未授权的证书,立即报告
4. 浏览器检查证书是否在 CT 日志中
5. 如果不在,显示警告
防护措施:证书固定(Certificate Pinning)
Public-Key-Pins: pin-sha256="base64=="; max-age=5184000
工作原理:
1. 网站指定信任的证书或公钥
2. 浏览器只接受这些证书
3. 即使攻击者有 CA 签发的证书,也会被拒绝
注意:配置错误可能导致网站无法访问,已逐渐被废弃
混合内容攻击
什么是混合内容:
<!-- HTTPS 页面中包含 HTTP 资源 -->
<!DOCTYPE html><html><head><!-- 危险:HTTP 脚本 -->
<script src="<http://example.com/script.js>"></script>
<!-- 危险:HTTP 样式 -->
<link rel="stylesheet" href="<http://example.com/style.css>"></head><body><!-- 警告:HTTP 图片 -->
<img src="<http://example.com/image.jpg>"></body></html>
安全风险:
主动混合内容(脚本、样式、iframe):
1. HTTPS 页面加载 HTTP 脚本
2. 攻击者可以修改 HTTP 脚本
3. 注入恶意代码
4. 窃取用户数据或执行恶意操作
5. HTTPS 的保护完全失效
被动混合内容(图片、音频、视频):
1. 攻击者可以替换图片
2. 可能显示钓鱼内容
3. 风险较小,但仍不安全
防护措施:
<!-- 1. 使用相对协议 URL -->
<script src="//example.com/script.js"></script><!-- 浏览器自动使用当前页面的协议 -->
<!-- 2. 使用 HTTPS URL -->
<script src="<https://example.com/script.js>"></script><!-- 3. 使用 CSP 升级不安全请求 -->
<meta http-equiv="Content-Security-Policy"content="upgrade-insecure-requests">
# 服务器端配置
Content-Security-Policy: upgrade-insecure-requests
# 自动将所有 HTTP 请求升级为 HTTPS
4. TLS 版本和加密套件
TLS 版本选择
不同版本的安全性:
SSL 2.0 / SSL 3.0:
- 已废弃,存在严重漏洞
- 必须禁用
TLS 1.0 / TLS 1.1:
- 存在已知漏洞(BEAST、POODLE)
- 主流浏览器已停止支持
- 应该禁用
TLS 1.2:
- 当前广泛使用
- 安全性良好
- 推荐使用
TLS 1.3:
- 最新版本
- 性能更好(握手更快)
- 安全性更强
- 强烈推荐
Nginx 配置示例:
server {
listen 443 ssl http2;
server_name 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:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384';
# 优先使用服务器端的加密套件
ssl_prefer_server_ciphers off; # TLS 1.3 不需要
# 证书文件
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /path/to/chain.pem;
# 会话缓存
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off; # 禁用 session tickets
# HSTS
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
# 其他安全头部
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
}
# HTTP 重定向到 HTTPS
server {
listen 80;
server_name example.com;
return 301 https://$server_name$request_uri;
}
HTTPS 安全配置检查清单
- 使用 TLS 1.2 或更高版本
- 禁用 SSL 2.0, SSL 3.0, TLS 1.0, TLS 1.1
- 使用强加密套件
- 启用 HSTS(包括 preload)
- 配置 OCSP Stapling
- 禁用 SSL Session Tickets
- 使用可信 CA 签发的证书
- 证书包含完整的证书链
- 配置自动证书续期
- 避免混合内容
- 使用 HTTP/2 或 HTTP/3
- 定期检查 SSL Labs 评分
安全建议
- 所有网站都应该使用 HTTPS
- 即使是静态网站
- 即使不处理敏感数据
- HTTPS 已成为 Web 标准
- 使用 HSTS 强制 HTTPS
- 设置合理的 max-age
- 包含 includeSubDomains
- 考虑加入 Preload List
- 定期更新 TLS 配置
- 关注安全公告
- 禁用不安全的协议和加密套件
- 使用 SSL Labs 测试
- 监控证书过期时间
- 设置提前提醒
- 使用自动续期(Let’s Encrypt + Certbot)
- 测试续期流程
- 避免混合内容
- 检查所有资源是否使用 HTTPS
- 使用 CSP upgrade-insecure-requests
- 在开发环境中测试
- 使用现代 HTTP 协议
- 启用 HTTP/2 或 HTTP/3
- 提高性能
- 增强安全性
- 定期安全审计
- 使用 SSL Labs 测试
- 检查证书配置
- 验证 HSTS 设置
- 扫描混合内容
