25、WebRTC安全加固:DTLS/SRTP加密优化、证书管理、防中间人攻击

WebRTC 的安全,说白了就是两件事:通信链路加密身份认证。很多人觉得 WebRTC 默认就加密了,不用操心。嗯,这话对了一半。默认确实有 DTLS 和 SRTP,但默认配置往往不是最优的,甚至可能留下安全隐患。

我早期参与过一个视频会议项目,上线后用户反馈偶尔出现「画面卡住几秒然后恢复」的情况。查了半天,发现是 DTLS 握手超时重传导致的。从那以后,我对安全层的性能调优就格外上心。

DTLS 握手:性能与安全的平衡点

DTLS 是 UDP 版的 TLS。它给每个数据包加了序列号和重传机制,解决 UDP 不可靠的问题。但代价就是握手延迟比 TCP 的 TLS 要高。

为什么会这样?因为 DTLS 握手需要 2-RTT,而且每个消息都可能丢包。丢包就得重传,重传就得等超时。默认超时时间通常是 1 秒,你想想看,如果网络稍微有点抖动,握手就可能拖到 3-4 秒。

核心优化点:缩短握手时间,同时保证安全性不降级。

1. 调整超时参数

在 OpenSSL/BoringSSL 中,可以设置 DTLS 的超时参数:

// 设置初始超时 500ms,最大超时 2s
SSL_CTX_set_timeout(ctx, 2);  // 单位:秒

// 更细粒度的控制(BoringSSL 示例)
DTLSv1_set_initial_timeout_duration(ctx, 500);  // 毫秒

我个人习惯把初始超时设为 500ms,最大重传次数设为 6 次。这样在弱网环境下,握手不会因为一次丢包就拖到 1 秒以上。

提示:不要设得太激进。初始超时低于 200ms 会导致不必要的重传,反而增加网络负载。

2. 启用会话复用

如果同一个用户频繁加入/离开房间(比如在线教育场景),每次重新握手是很浪费的。DTLS 支持会话复用,可以跳过完整的握手过程。

// 服务端保存会话
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_SERVER);

// 客户端复用会话
SSL_set_session(ssl, cached_session);

我在一个在线课堂项目中测试过,启用会话复用后,重连时间从 1.2 秒降到了 200 毫秒以内。效果非常明显。

SRTP 加密:选对算法很重要

SRTP 负责加密音视频数据。默认配置通常是 AES-128 的 Counter 模式。但这里有个坑:不同的 SRTP 实现,性能差异可能达到 3-5 倍

加密算法 密钥长度 性能(相对) 安全性
AES-128-CM 128 bit 基准
AES-256-CM 256 bit 慢 30-40% 更高
AES-128-GCM 128 bit 快 2-3 倍(硬件加速)
ChaCha20-Poly1305 256 bit 快 1.5-2 倍(无硬件加速)

我建议优先选择 AES-128-GCM。它支持硬件加速(AES-NI 指令集),在大多数现代 CPU 上性能最好。如果目标设备是低端手机或 IoT 设备,ChaCha20-Poly1305 是更好的选择——它不需要硬件加速,纯软件实现也很快。

警告:不要为了性能选择 NULL 加密(SRTP 允许不加密)。我曾经见过有人为了降低延迟关闭加密,结果用户隐私数据被中间人抓包。这是绝对不可接受的。

证书管理:自签名证书的坑与解法

WebRTC 允许使用自签名证书。但自签名证书有个问题:无法验证对端身份。中间人攻击最常用的手段就是伪造证书。

我记得有一次帮客户排查问题,发现他们的 WebRTC 应用在公网上被劫持了。原因就是用了自签名证书,而且没有做任何指纹校验。攻击者伪造了一个证书,客户端完全没察觉。

解决方案:指纹校验

在 DTLS 握手完成后,获取对端的证书指纹,与已知的合法指纹比对:

// 获取对端证书指纹
unsigned char fingerprint[EVP_MAX_MD_SIZE];
unsigned int len;
X509 *cert = SSL_get_peer_certificate(ssl);
X509_digest(cert, EVP_sha256(), fingerprint, &len);

// 与预置的合法指纹比对
if (memcmp(fingerprint, expected_fingerprint, len) != 0) {
    // 指纹不匹配,拒绝连接
    close_connection();
}

在实际项目中,我会把合法指纹通过信令通道(比如 WebSocket)提前交换。这样即使信令被劫持,攻击者也无法同时伪造 DTLS 证书和信令数据——除非他能同时攻破两个通道。

提示:指纹交换建议使用 SHA-256,不要用 SHA-1。SHA-1 已经被证明存在碰撞攻击风险。

防中间人攻击:多层防御

中间人攻击(MITM)是 WebRTC 安全的最大威胁。攻击者可以窃听、篡改甚至注入音视频流。防御 MITM 需要多层策略:

  1. 证书验证:使用受信任的 CA 证书,或严格校验自签名证书指纹。
  2. 信令通道加密:信令走 WSS(WebSocket Secure),不要用明文 WebSocket。
  3. DTLS-SRTP 绑定:确保 SRTP 的密钥来自 DTLS 握手,而不是单独协商。
  4. ICE 提名验证:在 ICE 连接建立后,验证候选地址是否与预期一致。

我曾经在项目中遇到过一种攻击:攻击者伪造了 STUN 响应,让客户端连接到错误的地址。后来我们加了 ICE 提名验证,每个候选地址都要经过信令通道确认,才彻底解决了这个问题。

知识体系总览

下面这张图总结了 WebRTC 安全加固的核心逻辑:

WebRTC 安全加固核心架构 传输层安全 DTLS 握手优化 · 超时调整 · 会话复用 媒体层加密 SRTP 算法选择 · AES-GCM / ChaCha20 · 密钥派生 身份认证 证书管理 · 指纹校验 · CA 信任链 防中间人攻击 多层防御 · 信令加密 · ICE 验证 · DTLS-SRTP 绑定

从传输层到防御层,每一层都环环相扣。你想想看,如果 DTLS 握手没优化好,后续的 SRTP 加密再强,用户体验也会很差。反过来,如果证书管理有漏洞,加密再强也防不住中间人。

总结一句话:WebRTC 安全不是「开了加密就完事」,而是需要从握手、加密、证书、防御四个维度持续优化。我在每个项目中都会把这四个点列成 checklist,上线前逐项检查。

公众号:蓝海资料掘金营,微信 deep3321