8. DTLS与SRTP:DTLS握手过程、SRTP密钥派生、媒体加密与安全协商

WebRTC 的媒体加密,说白了就是靠 DTLS 和 SRTP 这对黄金搭档。DTLS 负责握手、交换密钥,SRTP 负责用这些密钥加密实际的音视频数据。两者缺一不可。

我个人习惯把 DTLS 比作「安全信使」——它先跟对端打个招呼,确认身份,然后悄悄把密钥塞给 SRTP。SRTP 拿到密钥后,才开始真正干活:加密每一帧视频、每一段音频。

8.1 DTLS 握手过程

DTLS 是基于 UDP 的 TLS。为什么不用 TCP?因为 WebRTC 的媒体走的是 UDP,你不可能为了握手再开一条 TCP 连接。DTLS 就是在 UDP 上模拟 TLS 的可靠传输和握手流程。

握手过程大致分四步:

  1. ClientHello:发起方发送支持的加密套件、随机数等信息。
  2. ServerHello + 证书:响应方选择加密套件,发送自己的证书(通常是自签名证书)。
  3. 密钥交换:双方交换 DH 参数,计算出预主密钥。
  4. Finished:双方确认握手完成,开始派生 SRTP 密钥。

关键点:DTLS 握手过程中,双方会交换指纹(fingerprint)。指纹就是证书的哈希值,通过 SDP 的 a=fingerprint 字段传递。握手完成后,浏览器会比对证书指纹是否与 SDP 中的一致。不一致?直接断开。

我在项目中遇到过一个问题:自签名证书过期了,结果握手一直失败。排查了半天才发现是证书有效期的问题。嗯,这里要注意——DTLS 证书的有效期默认只有 30 天,很多浏览器会严格校验。

8.2 SRTP 密钥派生

DTLS 握手完成后,双方有了共享的 主密钥(Master Secret)。但 SRTP 不能直接用这个密钥,需要派生出一组子密钥。

派生过程遵循 RFC 5764,核心逻辑是:

  • 从主密钥 + 随机数(双方交换的)生成 SRTP 主密钥(16 字节或 32 字节)。
  • 再生成 SRTP 盐值(14 字节),用于初始化向量。
  • 最后生成 SRTP 认证密钥(20 字节),用于消息完整性校验。

说白了,就是一把钥匙开一把锁。DTLS 给了你一把万能钥匙,但 SRTP 需要三把专用钥匙。派生过程就是把这把万能钥匙拆成三把。

我的建议:如果你自己实现 WebRTC 的媒体加密层,千万别手动派生密钥。直接用 OpenSSL 或 BoringSSL 的 SSL_export_keying_material 函数。我曾经手写过一次派生逻辑,结果盐值长度算错了,导致解密失败。折腾了两天才发现。

8.3 媒体加密与安全协商

SRTP 加密的过程其实不复杂。每一帧 RTP 数据包到达时,SRTP 会做三件事:

  1. 加密载荷:用 AES 算法(通常是 AES-CM 或 AES-GCM)加密 RTP 的 payload 部分。
  2. 添加认证标签:在包末尾追加一个 HMAC-SHA1 或 AES-GCM 的认证标签,防止篡改。
  3. 更新序列号:SRTP 有自己的序列号管理机制,防止重放攻击。

你想想看,如果没有 SRTP,你的视频通话就是明文传输的。随便抓个包就能看到你在说什么、长什么样。SRTP 就是给这些数据穿上了一层防弹衣。

安全协商发生在 SDP 阶段。双方通过 a=cryptoa=setup 字段协商加密策略:

  • a=setup:active:当前端主动发起 DTLS 握手。
  • a=setup:passive:当前端被动等待握手。
  • a=setup:actpass:当前端既可以主动也可以被动,由对端决定。

避坑指南:我曾经遇到过一个兼容性问题——某些旧版浏览器只支持 a=crypto(SDES 方式),不支持 DTLS-SRTP。如果你强制使用 DTLS,对方直接拒绝连接。解决办法是在 SDP 中同时声明两种方式,让浏览器自己选。不过现在主流浏览器都只支持 DTLS-SRTP 了,SDES 基本被淘汰。

8.4 DTLS-SRTP 整体流程

我把整个流程画了一张图,方便你理解:

发起方 (Offerer) 响应方 (Answerer) ① SDP 交换 a=fingerprint:... a=setup:actpass ② DTLS 握手 ClientHello → ServerHello + 证书 → 密钥交换 → Finished ③ 密钥派生 (RFC 5764) SRTP 主密钥 SRTP 盐值 ④ SRTP 媒体加密 AES-CM/GCM 加密 + HMAC 认证

从图上可以看得很清楚:SDP 交换是前提,DTLS 握手是桥梁,密钥派生是核心,SRTP 加密是最终目的。每一步都环环相扣,缺一不可。

8.5 常见问题与排查思路

问题现象 可能原因 排查方法
DTLS 握手超时 UDP 被防火墙拦截,或证书过期 检查 UDP 端口 3478/5349 是否开放;检查证书有效期
指纹不匹配 SDP 中的指纹与实际证书不一致 重新生成 SDP,确保指纹字段正确
SRTP 解密失败 密钥派生参数不一致(如盐值长度错误) 对比双方的密钥派生日志,确认参数一致
媒体流黑屏/无声 SRTP 加密后未正确设置 RTP 头 抓包分析 RTP 包结构,检查加密标志位

我的经验:排查 DTLS 问题最有效的方法是抓包。用 Wireshark 过滤 dtlssrtp,一眼就能看出握手到哪一步失败了。我曾经遇到一个奇葩问题——双方 DTLS 握手成功,但 SRTP 就是解不出来。后来发现是其中一端的 OpenSSL 版本太旧,派生密钥时用了不同的哈希算法。升级后问题解决。

好了,DTLS 和 SRTP 的核心内容就这些。记住一句话:DTLS 负责安全握手,SRTP 负责安全传输。两者配合,才能保证你的音视频通话不被窃听、不被篡改。

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