RFC 2818 - 基于 TLS 的 HTTP (HTTPS) - 2. 基于 TLS 的 HTTP (HTTP Over TLS)
2. 基于 TLS 的 HTTP (HTTP Over TLS)
核心原则 (Core Principle)
概念上非常简单: HTTP/TLS 非常简单. 只需像在 TCP 上使用 HTTP 一样, 在 TLS 上使用 HTTP 即可.
2.1. 连接发起 (Connection Initiation)
过程:
1. 客户端 → 服务器: 建立 TCP 连接 (端口 443)
2. 客户端 → 服务器: 发送 TLS ClientHello
3. ↔ TLS 握手过程 ↔
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 握手完成 →
客户端:
10. 发送加密的 HTTP 请求:
GET / HTTP/1.1
Host: www.example.com
2.2. 连接关闭 (Connection Closure)
TLS 提供了安全关闭连接的功能.
关闭警报 (Closure Alert)
定义:
- 有效关闭 (Valid Closure): 收到正确的关闭警报
- 不完全关闭 (Incomplete Close): 发送关闭警报后立即关闭连接
- 提前关闭 (Premature Close): 未收到关闭警报即关闭连接
要求:
- ✅ 实现 MUST 在关闭连接之前发起关闭警报交换
- ⚠️ 实现 MAY 在发送关闭警报后关闭连接 (无需等待响应)
- ❌ 发生提前关闭的连接 MUST NOT 重用会话
2.2.1. 客户端行为 (Client Behavior)
问题: HTTP 使用连接关闭来表示服务器数据的结束.
客户端 MUST:
- ✅ 将任何提前关闭视为错误
- ✅ 将接收到的数据视为可能已被截断
- ✅ 在关闭连接之前发送关闭警报
特殊情况:
- 无 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)
RFC 2616 要求: 服务器 MUST 从客户端的关闭中优雅地恢复.
服务器 SHOULD:
- ✅ 准备好接收来自客户端的不完全关闭
- ✅ 愿意恢复以此种方式关闭的 TLS 会话
- ✅ 尝试与客户端交换关闭警报
- ⚡ MAY 在发送关闭警报后关闭连接
实现说明:
不使用持久连接的 HTTP:
- 服务器通过关闭连接来发出数据结束的信号
- 但客户端可能已经发送了关闭警报并断开连接
2.3. 端口号 (Port Number)
默认端口: 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 格式 (URI Format)
协议标识符: 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