传输层安全协议(TLS 1.3)有效抵御了链路监听者对网络通信载荷的窃听。然而,在端到端加密的表象之下,始终存在一个根深蒂固的元数据暴露漏洞:目标服务器必定能够获取发起请求的客户端IP地址。

在常规网页交互中,这种暴露被视作网络寻址的天然要求。但在涉及高敏感度场景时——例如向大语言模型提交推理提示词(Prompt)、上传系统崩溃诊断信息、发起生物特征验证或查询实时地理坐标——源IP地址往往充当着持久化数字指纹的角色。即便用户未登录任何平台账号,服务端系统只需聚合请求时间戳与IP地址,便足以构建高精度的用户行为画像。

传统的正向代理或SOCKS5中继并未解决信任根问题,仅将观测点转移至代理运营商处。为此,互联网工程任务组(IETF)正式发布了RFC 9458(Oblivious HTTP,简称OHTTP)标准,并与RFC 9180(Hybrid Public Key Encryption,HPKE)及RFC 9292(Binary HTTP)协同构建了无须集中式信任的隐私架构。

+--------------------------------------------------------------------------+
|                  RFC 9458 OBLIVIOUS HTTP (OHTTP) 架构示意图              |
+--------------------------------------------------------------------------+
|                                                                          |
|    +------------+        1. 发送加密请求报文 (HPKE)       +------------+ |
|    |            | --------------------------------------> |   中继     | |
|    |   客户端   | <-------------------------------------- |   服务器   | |
|    | (浏览器 /  |        4. 接收加密响应报文 (HPKE)       |  (Relay)   | |
|    |  AI Agent) |                                         +------------+ |
|    +------------+                                               |        |
|          |                                            2. 转发密 |3. 返回 |
|          | (客户端IP仅中继服务器可见)                 文报文    |加密响应|
|          | (载荷经目标端公钥加密,中继无法解密)                 v        |
|          |                                                +------------+ |
|          +----------------------------------------------> |   目标     | |
|                 (端到端密码学安全边界)                    |   服务器   | |
|                 目标端使用自身私钥解密业务报文            |  (Target)  | |
|                 目标端仅观测到中继服务器的IP地址          +------------+ |
|                                                                          |
+--------------------------------------------------------------------------+

密码学基石:HPKE混合加密与Binary HTTP封装

RFC 9458依托于中继方(Relay)与目标方(Target)之间的非共谋原则。中继方负责转发密文数据包,但无权解密查看内容;目标方解密并执行业务请求,但完全无法得知客户端的真实网络地址。

该架构建立在两项核心技术规范之上:

1. 二进制HTTP消息编码(RFC 9292)

传统的HTTP请求由ASCII文本行组成。在OHTTP体系中,包含请求方法、路径、标头与消息体的完整请求被序列化为紧凑且确定性的二进制字节数组(BHTTP):

+--------------------+--------------------------------+--------------------+
| 帧控制引导信息     | 索引化已知标头                 | 二进制有效载荷     |
| (GET /api/v1/query)| (Host: target.example.com ...) | (Binary payload)   |
+--------------------+--------------------------------+--------------------+

采用Binary HTTP消除了文本解析歧义,为后续的加密提供了规范化输入。

2. 混合公钥加密机制(HPKE, RFC 9180)

为防御中继方窥探,客户端使用目标方的公钥配置对BHTTP报文进行加密。目标方对外发布的OHTTP公钥配置包含:

  • key_id:1字节的密钥版本标识符,用于轮换管理;
  • kem_id:密钥封装机制(如Curve25519对应的0x0020);
  • kdf_id:密钥派生函数(如HKDF-SHA256对应的0x0001);
  • aead_id:关联数据认证加密算法(如AES-128-GCM或ChaCha20-Poly1305);
  • public_key:目标方原始公钥字节序列。

在HPKE基础模式下,客户端生成临时密钥对 $(sk_E, pk_E)$,并结合目标方公钥 $pk_T$ 计算共享密钥:

$$ ext{SharedSecret} = ext{DH}(sk_E, pk_T)$$

通过HKDF派生加密密钥 $K_{ ext{req}}$ 与随机数 $N_{ ext{req}}$ 后,客户端将二进制请求封密为密文 $C_{ ext{req}}$:

$$C_{ ext{req}} = ext{Seal}(K_{ ext{req}}, N_{ ext{req}}, ext{aad}, ext{BinaryHTTPRequest})$$

封装后的数据包以message/ohttp-req媒体类型发送至中继方,二进制结构为: [KeyID (1B)] || [KEM (2B)] || [KDF (2B)] || [AEAD (2B)] || [enc (32B)] || [密文]

由于解密私钥仅保存在目标方服务器上,中继方无法解析内部载荷,任何篡改均会导致AEAD校验失败。

+--------------------------------------------------------------------------+
|                     各参与实体的数据可见范围对照                         |
+--------------------------------------------------------------------------+
| 实体角色    | 能否获取客户端IP?    | 能否读取请求业务载荷? | 能否读取响应?|
+-------------+----------------------+-----------------------+-------------+
| 骨干网ISP   | 是                   | 否(TLS加密)         | 否          |
| 中继(Relay) | 是(或VPN出口IP)    | 否(HPKE高强度密文)  | 否          |
| 目标(Target)| 否(仅见中继服务器IP)| 是(解密后BHTTP)     | 是          |
+--------------------------------------------------------------------------+

Oblivious HTTP交互生命周期

OHTTP的标准请求响应流程分为五个阶段:

  1. 获取密钥配置:客户端通过DNS HTTPS记录或可信端点预先拉取目标方的OHTTP公钥。
  2. 报文二进制封装与加密:客户端将业务请求转换为BHTTP字节流,调用HPKE算法完成密文封密,输出message/ohttp-req数据体。
  3. 中继安全转发:客户端以HTTPS POST /relay方式发送数据包。中继方终止TLS连接,剥除源客户端的网络标头,向目标方发起新的HTTP请求完成投递。
  4. 目标方解密与业务处理:目标方依据key_id匹配私钥,通过enc还原共享密钥并解密提取BHTTP请求,执行业务逻辑(如AI模型推理),并将结果编码为BHTTP响应。
  5. 响应封装回传:目标方利用协商好的HPKE上下文密钥派生响应加密密钥 $K_{ ext{res}}$,生成message/ohttp-res数据包并返回给中继方,最终由客户端完成解密。

与RiceGuard及L3网络架构的技术协同

尽管OHTTP作用于应用层(L7),但当其与第三层(L3)网络隧道(如VPNRice的RiceGuard协议)组合时,构成了深层次的纵深防御体系:

  1. 消除中继侧画像风险:在通过RiceGuard隧道传输数据时,中继服务器看到的来源地址为VPN公用聚合节点,阻断了中继运营商针对物理宽带或蜂窝基站的定位追踪。
  2. 阻断DNS侧信道探测:中继域名与目标域名的解析完全在RiceGuard的内核隔离网络命名空间内完成,杜绝局域网设备推断OHTTP会话周期。
  3. 保护本地AI Agent推理外呼:本地运行的AI模型代理在执行工具调用(Tool Calling)与云端模型补充推理时,流量经由RiceGuard的OHTTP端点转发,使AI服务商无法保留客户端的IP网络标识。

客户端OHTTP封装实现参考(Go语言)

以下代码演示了客户端如何利用HPKE密码库将Binary HTTP载荷打包为合规的RFC 9458请求包:

package main

import (
	"bytes"
	"crypto/rand"
	"fmt"
	"io"
	"net/http"

	"github.com/cloudflare/circl/hpke"
)

type OHTTPEncapsulator struct {
	suite    hpke.Suite
	targetPK hpke.PublicKey
	keyID    uint8
}

func NewOHTTPEncapsulator(keyID uint8, kemID hpke.KEM, kdfID hpke.KDF, aeadID hpke.AEAD, rawPubKey []byte) (*OHTTPEncapsulator, error) {
	suite := hpke.NewSuite(kemID, kdfID, aeadID)
	pk, err := suite.KEM().Scheme().UnmarshalBinaryPublicKey(rawPubKey)
	if err != nil {
		return nil, fmt.Errorf("解析目标公钥失败: %w", err)
	}
	return &OHTTPEncapsulator{
		suite:    suite,
		targetPK: pk,
		keyID:    keyID,
	}, nil
}

// EncapsulateRequest 将BHTTP请求封装为RFC 9458二进制报文
func (oe *OHTTPEncapsulator) EncapsulateRequest(bhttpReq []byte) ([]byte, hpke.Context, error) {
	sender, err := oe.suite.NewSender(oe.targetPK, []byte("message/bhttp request"))
	if err != nil {
		return nil, nil, fmt.Errorf("初始化HPKE发送端失败: %w", err)
	}

	enc, ctx, err := sender.Setup(rand.Reader)
	if err != nil {
		return nil, nil, fmt.Errorf("建立HPKE上下文失败: %w", err)
	}

	ciphertext, err := ctx.Seal(nil, bhttpReq)
	if err != nil {
		return nil, nil, fmt.Errorf("密文封密失败: %w", err)
	}

	var buf bytes.Buffer
	buf.WriteByte(oe.keyID)
	buf.Write([]byte{0x00, 0x20}) // DHKEM(X25519, HKDF-SHA256)
	buf.Write([]byte{0x00, 0x01}) // HKDF-SHA256
	buf.Write([]byte{0x00, 0x01}) // AES-128-GCM
	buf.Write(enc)
	buf.Write(ciphertext)

	return buf.Bytes(), ctx, nil
}

func SendToRelay(relayURL string, targetURL string, ohttpPayload []byte) ([]byte, error) {
	req, err := http.NewRequest("POST", relayURL, bytes.NewReader(ohttpPayload))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "message/ohttp-req")
	req.Header.Set("Target", targetURL)

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("中继请求转发失败: %w", err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("中继节点拒绝处理: HTTP %d", resp.StatusCode)
	}

	return io.ReadAll(resp.Body)
}

工程权衡与部署考量

在实际架构设计中采用RFC 9458需综合平衡以下维度:

  • 网络往返延迟开销:由于数据包须途经两级实体(客户端 $ o$ 中继方 $ o$ 目标方),整体网络往返时间(RTT)通常增加20–45毫秒。该协议主要面向API数据交换与异步AI推理,不建议直接应用于高交互性重型网页浏览。
  • 缓存策略适配:CDN边缘缓存依赖URL明文。因OHTTP报文全面密文封装,中间节点需配置专用缓存控制头方可生效。
  • 运营独立性保障:中继方与目标方必须分属不同法人实体并部署在异构云环境中,杜绝任何共谋交换日志的可能性。

RFC 9458 Oblivious HTTP以优雅的数学方案确立了身份与数据的彻底分离,成为新一代互联网保密通信的重要范式。