RFC 2818 - HTTP Over TLS (HTTPS) (基于 TLS 的 HTTP (HTTPS))
- 状态: Informational
- 发布日期: May 2000
- Stream: IETF
- 被废弃: RFC9110
- 勘误: 无勘误
Abstract (摘要)
本备忘录描述了如何使用 Transport Layer Security (传输层安全, TLS) 来保护互联网上的 Hypertext Transfer Protocol (超文本传输协议, HTTP) 连接。当前的实际做法是将 HTTP 分层运行在 Secure Sockets Layer (安全套接层, SSL,即 TLS 的前身) 之上,通过使用不同的服务器端口来区分安全流量和非安全流量。本文档记录了使用 TLS 的这一实践。一份配套文档描述了在与普通 HTTP 相同的端口上使用 HTTP/TLS 的方法 [RFC2817]。
Importance (重要性)
RFC 2818 是 Web 安全的基石:
- 🔒 定义了 HTTPS 的基本机制
- 🌐 现代所有网站的安全基础
- 🔑 证书验证与身份确认
- ⚡ 安全连接的建立与关闭
1. Introduction (1. 引言)
HTTP [RFC2616] 最初是在互联网上以明文形式使用的。然而,随着 HTTP 在敏感应用中的使用增加,安全措施变得必不可少。SSL 及其继承者 TLS [RFC2246] 旨在提供面向通道的安全保护。本文档描述了如何使用基于 TLS 的 HTTP。
核心概念
HTTPS = HTTP + TLS
┌────────────────────────────────────────┐
│ HTTP/1.1 协议 │
│ (应用层协议) │
├────────────────────────────────────────┤
│ TLS/SSL 协议 │
│ (传输层安全) │
├────────────────────────────────────────┤
│ TCP 协议 │
│ (传输控制协议) │
└────────────────────────────────────────┘
1.1. Requirements Terminology (1.1. 需求术语)
本文档中出现的关键词 "MUST"、"MUST NOT"、"REQUIRED"、"SHOULD"、"SHOULD NOT" 和 "MAY" 应按照 [RFC2119] 中的描述进行解释。
2. HTTP Over TLS (2. 基于 TLS 的 HTTP)
Core Principle (核心原则)
概念上非常简单:HTTP/TLS 非常简单。只需像在 Transmission Control Protocol (传输控制协议, TCP) 上使用 HTTP 一样,在 TLS 上使用 HTTP 即可。
2.1. Connection Initiation (2.1. 连接发起)
过程:
1. 客户端 → 服务器:建立 TCP 连接 (端口 443)
2. 客户端 → 服务器:发送 TLS ClientHello
3. ↔ TLS 握手过程 (TLS Handshake Process) ↔
4. 握手完成后:客户端可以发起第一个 HTTP 请求
要求:
- ✅ HTTP 客户端扮演 TLS 客户端的角色
- ✅ 连接到适当的端口(默认 443)
- ✅ 发送 TLS ClientHello 以开始握手
- ✅ 所有 HTTP 数据 MUST 作为 TLS "应用数据 (application data)" 发送
流程示例:
客户端:
1. TCP 连接到 www.example.com:443
2. 发送 ClientHello
服务器:
3. 响应 ServerHello + Certificate (证书)
4. ServerHelloDone
客户端:
5. ClientKeyExchange (客户端密钥交换)
6. ChangeCipherSpec (更改密码规范)
7. Finished (完成)
服务器:
8. ChangeCipherSpec (更改密码规范)
9. Finished (完成)
← TLS 握手完成 (TLS Handshake Complete) →
客户端:
10. 发送加密的 HTTP 请求:
GET / HTTP/1.1
Host: www.example.com
2.2. Connection Closure (2.2. 连接关闭)
TLS 提供了安全关闭连接的功能。
Closure Alert (关闭警报)
定义:
- 有效关闭 (Valid Closure):收到正确的关闭警报 (closure alert)
- 不完全关闭 (Incomplete Close):发送关闭警报后立即关闭连接
- 提前关闭 (Premature Close):未收到关闭警报即关闭连接
要求:
- ✅ 实现 MUST 在关闭连接之前发起关闭警报交换
- ⚠️ 实现 MAY 在发送关闭警报后关闭连接(无需等待响应)
- ❌ 发生提前关闭的连接 MUST NOT 重用会话 (session)
2.2.1. Client Behavior (2.2.1. 客户端行为)
问题:HTTP 使用连接关闭来表示服务器数据的结束。
客户端 MUST:
- ✅ 将任何提前关闭视为错误
- ✅ 将接收到的数据视为可能已被截断 (potentially truncated)
- ✅ 在关闭连接之前发送关闭警报
特殊情况:
- 无 Content-Length 的响应:
HTTP/1.1 200 OK
Content-Type: text/html
[连接关闭表示结束]
← 提前关闭无法区分是服务器正常关闭还是攻击者干预 →
- 有 Content-Length 但未完全读取:
HTTP/1.1 200 OK
Content-Length: 1000
[在关闭前仅收到 500 字节]
← 无法确定是服务器发生错误还是遭受攻击 →
异常处理:如果接收到的数据与 Content-Length 相匹配,则应视为完整。
客户端示例:
✅ 正常关闭:
客户端: 发送 closure_alert
等待服务器的 closure_alert
关闭连接
⚡ 快速关闭:
客户端: 发送 closure_alert
立即关闭连接(不等待)
← 这将在服务器端产生“不完全关闭” →
2.2.2. Server Behavior (2.2.2. 服务器行为)
RFC 2616 要求:服务器 MUST 从客户端的关闭中优雅地恢复。
服务器 SHOULD:
- ✅ 准备好接收来自客户端的不完全关闭
- ✅ 愿意恢复以此种方式关闭的 TLS 会话
- ✅ 尝试与客户端交换关闭警报
- ⚡ MAY 在发送关闭警报后关闭连接
实现说明:
不使用持久连接的 HTTP:
- 服务器通过关闭连接来发出数据结束的信号
- 但客户端可能已经发送了关闭警报并断开连接
2.3. Port Number (2.3. 端口号)
默认端口:443
原理:
HTTP 服务器期望:请求行 (Request-Line)(例如,GET / HTTP/1.1)
TLS 服务器期望:ClientHello
← 无法在同一个端口上进行区分 →
解决方案:使用不同的端口
- HTTP: 80
- HTTPS: 443
示例:
# HTTP (明文)
curl http://www.example.com:80/
# HTTPS (加密)
curl https://www.example.com:443/
2.4. URI Format (2.4. URI 格式)
协议标识符:https://(而非 http://)
示例:
https://www.example.com/~smith/home.html
https://api.example.com:8443/v1/users
https://192.168.1.1/admin
URI 组成部分:
https://www.example.com:443/path?query#fragment
↑ ↑ ↑ ↑ ↑ ↑
协议方案(scheme) 主机(host) 端口(port) 路径(path) 查询(query) 片段(fragment)
3. Endpoint Identification (3. 端点识别)
3.1. Server Identity (3.1. 服务器身份)
核心要求:客户端 MUST 验证服务器身份,以防止 Man-in-the-Middle Attack (中间人攻击, MITM)。
身份验证过程
1. 客户端从 URI 中获取主机名 (hostname)
例如: https://www.example.com
2. 服务器在 TLS 握手期间提供证书
3. 客户端检查主机名是否与证书中的身份匹配
身份字段优先级
优先级 1: subjectAltName (主题备用名称, SAN)
证书中的 subjectAltName 扩展(dNSName 类型):
dNSName: www.example.com
dNSName: api.example.com
← MUST 使用此字段(如果存在) →
优先级 2: Common Name (通用名称, CN)
证书 Subject 字段中的 CN:
CN=www.example.com
← 仅在不存在 subjectAltName 时使用 →
← 已弃用,证书颁发机构 (Certificate Authority, CA) 应当使用 dNSName →
匹配规则
1. 通配符匹配 (Wildcard Matching):
证书: *.example.com
✅ 匹配: foo.example.com
❌ 不匹配: bar.foo.example.com
证书: f*.com
✅ 匹配: foo.com
❌ 不匹配: bar.com
2. IP 地址:
URI: https://192.168.1.1/
证书必须包含: iPAddress 类型的 subjectAltName
值必须完全匹配: 192.168.1.1
3. 多个身份:
如果证书包含多个 dNSName:
- www.example.com
- api.example.com
- *.app.example.com
← 匹配其中任何一个都是可以接受的 →
未匹配时的行为
面向用户的客户端(如浏览器):
- ✅ MUST 通知用户
- ⚠️ MAY 允许用户选择是否继续连接
- 或者终止连接
自动化客户端(如 API 客户端):
- ✅ MUST 将错误记录到审计日志中
- ✅ SHOULD 终止连接
- ⚠️ MAY 提供配置选项来禁用此检查
安全警告 (Security Warning)
不可信的 URI 来源:
攻击场景:
1. 用户点击 HTTP 页面中的链接
2. HTTP 页面本身是未加密的
3. 中间人可能已经替换了该 URI
防护措施:
用户应当仔细检查服务器证书
3.2. Client Identity (3.2. 客户端身份)
典型情况:服务器不具备关于客户端身份 of 外部已知信息。
如果服务器具备外部已知信息(来自 HTTP 或 TLS 之外):
- 应当按照上述方式检查身份。
客户端证书认证 (Client Certificate Authentication):
常见场景:
- 企业内部系统
- API 访问控制
- Mutual TLS (双向 TLS, mTLS)
验证:
- 证书链植根于适当的 CA
- 可选:验证特定的客户端身份
Security Considerations (安全考虑)
本文档的全部内容都与安全有关。
关键安全点
-
证书验证是强制性的
- 客户端 MUST 验证服务器证书
- 防止中间人攻击
-
正确的连接关闭
- 使用 TLS 关闭警报
- 检测数据截断攻击 (data truncation attacks)
-
主机名验证
- 防止证书替换攻击
- 相比于 CN,优先使用 subjectAltName
-
发不可信的 URI
- 通过 HTTP 获取的 URI 可能会被篡改
- 用户应当仔细检查证书
Practical Examples (实用示例)
完整的 HTTPS 连接
客户端操作:
1. 解析 URI: https://www.example.com/page.html
→ 主机名 (Hostname): www.example.com
→ 端口号 (Port): 443 (默认)
2. TCP 连接到 www.example.com:443
3. TLS 握手:
ClientHello →
← ServerHello + Certificate
验证证书中的主机名
...握手完成...
4. 发送加密的 HTTP 请求:
GET /page.html HTTP/1.1
Host: www.example.com
5. 接收加密的 HTTP 响应:
HTTP/1.1 200 OK
Content-Length: 1234
...
6. 关闭连接:
发送 closure_alert
关闭 TCP 连接
证书验证示例
# Python 示例 (概念性)
import ssl
import socket
# 创建 SSL 上下文 (context)
context = ssl.create_default_context()
# 连接到服务器
sock = socket.create_connection(('www.example.com', 443))
ssock = context.wrap_socket(sock, server_hostname='www.example.com')
# wrap_socket 会自动验证:
# 1. 证书链是有效的
# 2. 主机名匹配
# 3. 证书未过期
# 获取证书信息
cert = ssock.getpeercert()
print(f"Subject: {cert['subject']}")
print(f"Issuer: {cert['issuer']}")
print(f"SANs: {cert.get('subjectAltName', [])}")
Common Error Handling (常见错误处理)
错误 1: Certificate Hostname Mismatch (证书主机名不匹配)
- 证书: *.example.com
- 访问: www.different.com
→ 终止连接或警告用户
错误 2: Certificate Expired (证书已过期)
- 过期时间 (Not After): 2023-12-31
- 当前时间 (Current): 2024-01-01
→ 拒绝连接
错误 3: Self-Signed Certificate (自签名证书)
- 不在受信任的 CA 列表中
→ 警告用户或拒绝连接
错误 4: Incomplete Certificate Chain (证书链不完整)
- 缺少中间证书 (intermediate certificate)
→ 无法验证,拒绝连接
Relationship to Modern Standards (与现代标准的关系)
Successors to RFC 2818 (RFC 2818 的后续标准)
虽然 RFC 2818 仍然有效,但已有更新的规范:
| RFC | 标题 | 说明 |
|---|---|---|
| RFC 2818 | HTTP Over TLS | 本文档 (2000年) |
| RFC 5246 | TLS 1.2 | 更新的 TLS 协议 |
| RFC 8446 | TLS 1.3 | 最新的 TLS 协议 |
| RFC 6125 | Certificate Validation | 更详细的主机名验证规范 |
| RFC 7230-7235 | HTTP/1.1 | 更新的 HTTP 规范 |
| RFC 7540 | HTTP/2 | HTTP/2 通常运行在 TLS 之上 |
Modern Practice Updates (现代实践更新)
- TLS 版本:
RFC 2818: SSL/TLS (1.0/1.1)
现代实践: TLS 1.2+ (TLS 1.0/1.1 已弃用)
- 证书验证:
RFC 2818: 基本规则
RFC 6125: 详细规范
- HSTS:
RFC 6797: HTTP Strict Transport Security (HTTP 严格传输安全, HSTS)
强制浏览器使用 HTTPS
Quick Reference (快速参考)
HTTPS vs HTTP
| 特性 | HTTP | HTTPS |
|---|---|---|
| 协议 | http:// | https:// |
| 端口 | 80 | 443 |
| 加密性 | ❌ 明文 (Cleartext) | ✅ TLS 加密 |
| 完整性 | ❌ 无保护 | ✅ MAC (消息验证码) 保护 |
| 认证性 | ❌ 无服务器认证 | ✅ 证书认证 |
| 隐私性 | ❌ 可被窃听 | ✅ 加密传输 |
TLS Handshake Overview (TLS 握手概述)
客户端 (Client) 服务器 (Server)
| |
|--- ClientHello --------------->|
| |
|<-- ServerHello, Certificate ---|
|<-- ServerHelloDone ------------|
| |
|--- ClientKeyExchange --------->|
|--- ChangeCipherSpec ---------->|
|--- Finished ------------------>|
| |
|<-- ChangeCipherSpec -----------|
|<-- Finished -------------------|
| |
|=== 加密通道 (Encrypted Channel) ===|
| |
|--- 加密 HTTP 请求 ------------>|
|<-- 加密 HTTP 响应 -------------|
Common Tools (常见工具)
# OpenSSL 查看证书
openssl s_client -connect www.example.com:443 -showcerts
# 测试 TLS 版本
openssl s_client -connect www.example.com:443 -tls1_2
# 查看证书详细信息
echo | openssl s_client -connect www.example.com:443 2>/dev/null | \
openssl x509 -noout -text
# cURL 使用 HTTPS
curl -v https://www.example.com
References (参考文献)
Normative References (规范性引用文件)
- [RFC 2119] - Key words for use in RFCs to Indicate Requirement Levels (在 RFC 中用于表示需求级别的关键词)
- [RFC 2246] - The TLS Protocol (TLS 协议)
- [RFC 2459] - Internet X.509 Public Key Infrastructure Certificate and CRL Profile (互联网 X.509 公钥基础设施证书及 CRL 轮廓)
- [RFC 2616] - Hypertext Transfer Protocol -- HTTP/1.1 (超文本传输协议 -- HTTP/1.1)
Informative References (资料性引用文件)
- [RFC 2817] - Upgrading to TLS Within HTTP/1.1 (在 HTTP/1.1 中升级到 TLS)
- [RFC 5246] - The Transport Layer Security (TLS) Protocol Version 1.2 (传输层安全 (TLS) 协议版本 1.2)
- [RFC 6125] - Representation and Verification of Domain-Based Application Service Identity (基于域的应用服务身份的表示与验证)
- [RFC 6797] - HTTP Strict Transport Security (HSTS) (HTTP 严格传输安全)
- [RFC 7230-7235] - Hypertext Transfer Protocol (HTTP/1.1) Updated Specifications (超文本传输协议 (HTTP/1.1) 更新规范)
- [RFC 8446] - The Transport Layer Security (TLS) Protocol Version 1.3 (传输层安全 (TLS) 协议版本 1.3)
Glossary (术语表)
Core Terms (核心术语)
TLS (Transport Layer Security,传输层安全)
- 传输层安全协议,为 SSL 的继承者
SSL (Secure Sockets Layer,安全套接层)
- TLS 的前身,现已弃用
Certificate (证书)
- 包含公钥和身份信息的数字文档
CA (Certificate Authority,证书颁发机构)
- 颁发可信证书的证书管理机构
Closure Alert (关闭警报)
- 用于安全关闭连接的 TLS 机制
Premature Close (提前关闭)
- 不规范 of TLS 连接关闭
Man-in-the-Middle Attack (中间人攻击)
- 攻击者拦截并可能修改通信内容的攻击方式
subjectAltName (主题备用名称)
- 指定额外主机名的证书扩展字段
Common Name (通用名称)
- 证书主题 (subject) 中的 CN 字段
返回: RFC 文档列表
相关 RFC: