跳到主要内容

RFC 2818 - 基于 TLS 的 HTTP (HTTPS)

  • 状态: Informational
  • 发布日期: May 2000
  • Stream: IETF
  • 被废弃: RFC9110
  • 勘误: 无勘误

摘要 (Abstract)

本备忘录描述了如何使用 TLS 保护 Internet 上的 HTTP 连接. 当前的实际做法是将 HTTP 分层运行在 SSL (TLS 的前身) 之上, 通过使用不同的服务器端口来区分安全流量与非安全流量. 本文档记录了使用 TLS 的这一实践. 一份配套文档描述了在与普通 HTTP 相同的端口上使用 HTTP/TLS 的方法 [RFC2817].

重要性 (Importance)

RFC 2818 是 Web 安全的基石:

  • 🔒 定义了 HTTPS 的基本机制
  • 🌐 现代所有网站的安全基础
  • 🔑 证书验证与身份确认
  • ⚡ 安全连接的建立与关闭

1. 引言 (Introduction)

HTTP [RFC2616] 最初在 Internet 上以明文形式使用. 然而, 随着 HTTP 在敏感应用中的使用增加, 安全措施变得必不可少. SSL 及其后继者 TLS [RFC2246] 旨在提供面向通道的安全保护. 本文档描述了如何在 TLS 上使用 HTTP.

核心概念 (Core Concept)

HTTPS = HTTP + TLS

┌────────────────────────────────────────┐
│ HTTP/1.1 协议 │
│ (应用层协议) │
├────────────────────────────────────────┤
│ TLS/SSL 协议 │
│ (传输层安全) │
├────────────────────────────────────────┤
│ TCP 协议 │
│ (传输控制协议) │
└────────────────────────────────────────┘

1.1. 需求术语 (Requirements Terminology)

本文档中出现的关键词 "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT" 和 "MAY" 应按照 [RFC2119] 中的描述进行解释.


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:

  • ✅ 将任何提前关闭视为错误
  • ✅ 将接收到的数据视为可能已被截断
  • ✅ 在关闭连接之前发送关闭警报

特殊情况:

  1. 无 Content-Length 的响应:
HTTP/1.1 200 OK
Content-Type: text/html
[连接关闭表示结束]

← 提前关闭无法区分是服务器正常关闭还是攻击者干预 →
  1. 有 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

3. 端点识别 (Endpoint Identification)

3.1. 服务器身份 (Server Identity)

核心要求: 客户端 MUST 验证服务器身份, 以防止中间人攻击 (man-in-the-middle).

身份验证过程 (Identity Verification Process)

1. 客户端从 URI 中获取主机名
例如: https://www.example.com

2. 服务器在 TLS 握手期间提供证书

3. 客户端检查主机名是否与证书中的身份匹配

身份字段优先级 (Identity Field Priority)

优先级 1: subjectAltName (主题备用名称)

证书中的 subjectAltName 扩展 (dNSName 类型):
dNSName: www.example.com
dNSName: api.example.com

← MUST 使用此字段 (如果存在) →

优先级 2: Common Name (通用名称)

证书 Subject 字段中的 CN:
CN=www.example.com

← 仅在不存在 subjectAltName 时使用 →
← 已弃用, CA 应当使用 dNSName →

匹配规则 (Matching Rules)

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

← 匹配其中任何一个都是可以接受的 →

未匹配时的行为 (Behavior When No Match)

面向用户的客户端 (如浏览器):

  • ✅ MUST 通知用户
  • ⚠️ MAY 允许用户选择是否继续连接
  • 或者终止连接

自动化客户端 (如 API 客户端):

  • ✅ MUST 将错误记录到审计日志中
  • ✅ SHOULD 终止连接
  • ⚠️ MAY 提供配置选项来禁用此检查

安全警告 (Security Warning)

不可信的 URI 来源:

攻击场景:
1. 用户点击 HTTP 页面中的链接
2. HTTP 页面本身是未加密的
3. 中间人可能已经替换了该 URI

防护措施:
用户应当仔细检查服务器证书

3.2. 客户端身份 (Client Identity)

典型情况: 服务器通常没有关于客户端身份的外部已知信息.

如果服务器具备外部已知信息 (来自 HTTP 或 TLS 之外):

  • 应当按照上述方式检查身份

客户端证书认证:

常见场景:
- 企业内部系统
- API 访问控制
- Mutual TLS (双向 TLS, mTLS)

验证:
- 证书链植根于适当的 CA
- 可选: 验证特定的客户端身份

安全考虑 (Security Considerations)

本文档的全部内容都与安全有关.

关键安全点 (Key Security Points)

  1. 证书验证是强制性的

    • 客户端 MUST 验证服务器证书
    • 防止中间人攻击
  2. 正确的连接关闭

    • 使用 TLS 关闭警报
    • 检测数据截断攻击
  3. 主机名验证

    • 防止证书替换攻击
    • 相比于 CN, 优先使用 subjectAltName
  4. 警惕不可信的 URI

    • 通过 HTTP 获取的 URI 可能会被篡改
    • 用户应当仔细检查证书

实用示例 (Practical Examples)

完整的 HTTPS 连接 (Complete HTTPS Connection)

客户端操作:

1. 解析 URI: https://www.example.com/page.html
→ 主机名: www.example.com
→ 端口: 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 连接

证书验证示例 (Certificate Verification Example)

# Python 示例 (概念性)
import ssl
import socket

# 创建 SSL 上下文
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)
- 缺少中间证书
→ 无法验证, 拒绝连接

与现代标准的关系 (Relationship to Modern Standards)

RFC 2818 的后续标准 (Successors to RFC 2818)

虽然 RFC 2818 仍然有效, 但已有更新的规范:

RFC标题说明
RFC 2818HTTP Over TLS本文档 (2000)
RFC 5246TLS 1.2更新的 TLS 协议
RFC 8446TLS 1.3最新的 TLS 协议
RFC 6125Certificate Validation更详细的主机名验证
RFC 7230-7235HTTP/1.1更新的 HTTP 规范
RFC 7540HTTP/2HTTP/2 通常运行在 TLS 之上

现代实践更新 (Modern Practice Updates)

  1. TLS 版本:
RFC 2818: SSL/TLS (1.0/1.1)
现代实践: TLS 1.2+ (TLS 1.0/1.1 已弃用)
  1. 证书验证:
RFC 2818: 基本规则
RFC 6125: 详细规范
  1. HSTS:
RFC 6797: HTTP Strict Transport Security
强制浏览器使用 HTTPS

快速参考 (Quick Reference)

HTTPS vs HTTP

特性HTTPHTTPS
协议http://https://
端口80443
加密❌ 明文✅ TLS 加密
完整性❌ 无保护✅ MAC 保护
认证❌ 无服务器认证✅ 证书认证
隐私❌ 可被窃听✅ 加密传输

TLS 握手概述 (TLS Handshake Overview)

客户端                           服务器
| |
|--- ClientHello --------------->|
| |
|<-- ServerHello, Certificate ---|
|<-- ServerHelloDone ------------|
| |
|--- ClientKeyExchange --------->|
|--- ChangeCipherSpec ---------->|
|--- Finished ------------------>|
| |
|<-- ChangeCipherSpec -----------|
|<-- Finished -------------------|
| |
|=== 加密通道 ===================|
| |
|--- 加密 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 2246] - The TLS Protocol
  • [RFC 2459] - Internet X.509 Public Key Infrastructure Certificate and CRL Profile
  • [RFC 2616] - Hypertext Transfer Protocol -- HTTP/1.1

资料性引用 (Informative References)

  • [RFC 2817] - Upgrading to TLS Within HTTP/1.1
  • [RFC 5246] - The Transport Layer Security (TLS) Protocol Version 1.2
  • [RFC 6125] - Representation and Verification of Domain-Based Application Service Identity
  • [RFC 6797] - HTTP Strict Transport Security (HSTS)
  • [RFC 7230-7235] - Hypertext Transfer Protocol (HTTP/1.1) Updated Specifications
  • [RFC 8446] - The Transport Layer Security (TLS) Protocol Version 1.3

术语表 (Glossary)

核心术语 (Core Terms)

TLS (Transport Layer Security)

  • 传输层安全协议, SSL 的后继者

SSL (Secure Sockets Layer)

  • TLS 的前身, 现已弃用

Certificate (证书)

  • 包含公钥和身份信息的数字文档

CA (Certificate Authority)

  • 颁发可信证书的证书颁发机构

Closure Alert (关闭警报)

  • 用于安全关闭连接的 TLS 机制

Premature Close (提前关闭)

  • 不规范的 TLS 连接关闭

Man-in-the-Middle Attack (中间人攻击)

  • 攻击者拦截并可能修改通信内容

subjectAltName (主题备用名称)

  • 指定额外主机名的证书扩展

Common Name (通用名称)

  • 证书 Subject 中的 CN 字段

返回: RFC 文档列表

相关 RFC: