我正在参加「RTE 实时万象」征文活动,活动参见 https://www.agora.io/cn/community/blog/25197 。
一、目标
保证媒体安全的核心首要目标是保证用户的数据安全,如何达成这一目标呢?具体措施分五点:
- 信令协商:SDP协商时,采用经典TLS协议,避免信息泄露、篡改和伪造。
- 身份认证:STUN/DTLS链路上下文关联到SDP协商链路,实现身份认证,避免中间人攻击
- 密钥协商:媒体加密的对称密钥采用非对称密钥链路传递,避免媒体加密密钥泄露
- 媒体加密:媒体数据采用对称密钥加密,避免抓包窃听通话内容,并且防止重放攻击
- 完整性保护:校验协商数据的完整性,避免协商数据被其他人篡改
总之,是确保用户连接到一个正确的服务器,而且数据链路安全可靠,最终使正确的媒体数据发送到指定的用户端应用程序。
二、实现手段
信令协商
信令协商指sdp协商,通常采用websockets或者https链路,上传localSDP到服务端,并获取服务端的remoteSDP,基于经典的TLS协议底层安全机制保障实现信令协商的安全,可以参考RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2这个互联网协议标准。具体机制如下:
注意一点,这与WebRTC的证书校验方式不同,这里客户端校验服务端的方式是:校验证书域名是否一致,核查证书域名是否与当前的访问域名匹配,并且证书是由权威的第三方CA机构颁发的。
身份认证
WebRTC服务端身份认证的方法是采用建链首包STUN协议,参考RFC 5245: Interactive Connectivity Establishment (ICE)协议:
- USERNAME属性是sdp的ice-ufrag组成的,服务端根据USERNAME关联到sdp协商的会话。
- MESSAGE-INTEGRITY属性是“sdp的ice-pwd + stun消息体”进行HMAC摘要计算得出,服务端根据MESSAGE-INTEGRITY计算消息完整性,同时防止伪造的客户端接入。
WebRTC客户端身份认证方法是采用DTLS协议,参考RFC 8842: Session Description Protocol (SDP)与Datagram Transport Layer Security (DTLS) 的关系,SDP中a=fingerprint 的内容是证书的摘要签名,用于验证证书的有效性,防止中间人冒充假的服务端。
密钥协商
WebRTC媒体密钥非对称密钥协商握手协议也是采用DTLS协议,参考RFC 4347: Datagram Transport Layer Security (DTLS)协议,协商机制与TLS的机制基本一样,如下:
媒体加密
- WebRTC的媒体数据加密协议采用的是SRTP协议,参考RFC 3711: The Secure Real-time Transport Protocol (SRTP)定义协议,并且参考RFC 5763建链SRTP与DTLS之间的联系。总之,SRTP获取到DTLS协商生成的对称密钥,再加密媒体数据。
- 在防止重放攻击方面,SRTP 解密端通过维护一个重放列表 (ReplayList) 缓存,来区分新包、乱序包和重放包,使用滑动窗口(sliding window)来识别重放包,并通过CTR(Counter mode)流式密钥的方式变换密钥,防止重放攻击。
完整性保护
- STUN包:参考RFC 5245 STUN的请求和响应包,都有FINGERPRINT指纹属性,通过CRC-32循环冗余校验来检测数据传输过程中是否发生了错误。
- DTLS包:握手阶段无数据完整性保护,而在data channel通道传输数据时,采用HMAC对record层的数据包完整性进行校验。
- SRTP包:通过SRTP的推荐字段Authentication Tag进行完整性验证。加密端将RTP数据头与RTP的加密数据做一次Hash函数运算,计算出摘要,附加在加密数据尾部Authentication Tag上,用于解码端验证。
三、一点思考
由于WebRTC作为浏览器的重要多媒体通信的入口,在保证用户数据安全的前提下,优先考虑的是协议的标准、通用和兼容,所以上述五点安全措施均采用标准的RFC协议实现。而商业化公司构建自身的实时通信系统时,可以适度牺牲标准兼容能力,而在性能优化、业务贴合方面考虑优化点。例如把信令、身份认证和密钥协商统一到一个阶段,以减少信息交互,实现0RTT建链;或者增加信令传输的前向纠错(FEC)机制,以保证建链的成功率和低延迟等。最终目标是既满足了用户数据的安全要求,又能实现了用户体验的优化与提升。