WebRTC 全景实战 (7):DTLS 握手与 SRTP 加密体系
Ch5 ICE 连通 UDP 通道后,媒体并非明文传输。WebRTC 强制走 DTLS 握手 → 导出 SRTP 密钥 → 加密 RTP,这是 RFC 8827 WebRTC Security Architecture 的核心要求。
理解这一层的设计意图:Gmail 语音视频聊天时代,安全是事后补丁;WebRTC 从标准化之初就将 默认加密 作为不可协商的底线(参见 Curious — WebRTC 历史 中「安全是重中之重」)。Google 工程师在 2010 年前后推动 DTLS-SRTP 成为唯一媒体保护方案,彻底告别了早期 VoIP 明文 RTP 的惯例。
Curious 历史 中,Serge Lachapelle 回忆:收购 GIPS 后,团队内部曾激烈讨论「是否允许开发者关闭加密」。最终结论是一刀切——媒体必须加密,没有开关。这一决策直接写进了 RFC 8827:a=crypto(SDES)被废弃,DTLS-SRTP 是唯一允许的密钥协商方式。对开发者而言,这意味着你永远不会在 chrome://webrtc-internals 里看到明文 RTP 载荷——除非主动做 E2EE 之上的二次加密。
本章覆盖 RFC 6347 DTLS 握手、RFC 5764 密钥导出、RFC 3711 SRTP 包处理、Certificate Fingerprint 验证,以及 Insertable Streams 端到端加密入门。
本篇术语表
| 术语 | 英文 | 解释 |
|---|---|---|
| DTLS | Datagram Transport Layer Security | 在 UDP 上运行的 TLS 变体,RFC 6347 定义 |
| SRTP | Secure Real-time Transport Protocol | RTP 的加密扩展,RFC 3711 定义 |
| SRTCP | Secure RTCP | RTCP 控制包的加密版本,与 SRTP 共用密钥材料 |
| DTLS-SRTP | — | 从 DTLS 握手导出 SRTP 密钥的 profile,RFC 5764 |
| Fingerprint | Certificate Fingerprint | SDP a=fingerprint 中声明的证书哈希,绑定信令与 DTLS |
| Master Secret | — | DTLS 握手协商出的主密钥,经 KDF 导出 SRTP 密钥 |
| SRTP Master Key | — | 用于加密单个 RTP 会话的对称密钥(128/256 bit) |
| SRTP Salt | — | 与 Master Key 配合使用的盐值,参与 IV 派生 |
| Authentication Tag | — | SRTP 包尾的 MAC,验证完整性与真实性 |
| AEAD | Authenticated Encryption with Associated Data | 现代 SRTP 加密模式(AES-GCM),同时提供加密与认证 |
| use_srtp | DTLS Extension | 告知对端握手完成后密钥用于 SRTP 而非 DTLS 应用数据 |
| setup | SDP Attribute | DTLS 角色:active/passive/actpass |
| Hop-by-hop | — | 默认模式:SFU 解密再加密,中间节点可见明文 |
| E2EE | End-to-End Encryption | 端到端加密,中间 SFU 无法解密 |
| Insertable Streams | — | WebRTC Encoded Transform API,在编码帧上插入自定义加密 |
一、安全栈在协议栈中的位置
WebRTC 媒体路径上的安全是分层的:ICE 只解决「包能送到哪」,DTLS 解决「密钥如何协商」,SRTP 解决「每个 RTP 包如何加密」。
| 层 | 标准 | 作用 |
|---|---|---|
| DTLS | RFC 6347 | 在 UDP 上完成 TLS 式握手,协商密钥 |
| DTLS-SRTP | RFC 5764 | 从 DTLS 导出 SRTP 会话密钥 |
| SRTP | RFC 3711 | RTP 包加密(AES-CM / AEAD)与认证(HMAC-SHA1) |
| SRTCP | RFC 3711 | RTCP 控制包同样加密 |
HTTPS = TLS over TCP,WebRTC = DTLS over UDP。UDP 不保证顺序和可靠送达,DTLS 必须处理丢包、重传和乱序——这也是为什么 DTLS 握手必须在 ICE 连通之后、RTP 发送之前完成。
与 Ch6 Data Channel 对比:Data Channel 走 SCTP over DTLS(应用数据在 DTLS 记录层内传输),而音视频走 DTLS-SRTP(DTLS 只用于密钥协商,媒体数据在 SRTP 层加密后直发 UDP)。
1.1 为什么不用 TLS?
TCP 的三次握手 + 队头阻塞与实时媒体不兼容。ICE 已经选定了 UDP 五元组,在此之上叠加 DTLS 是自然选择。DTLS 1.2 是 WebRTC 的强制基线;DTLS 1.3 在部分实现中逐步引入,但核心密钥导出逻辑仍遵循 RFC 5764 profile。
1.2 SAVPF 与 SRTP 的关系
Ch4 SDP 中 m-line 的 UDP/TLS/RTP/SAVPF 已经声明了完整协议栈:
- TLS → 实际指 DTLS
- SAVP → Secure AV Profile(SRTP)
- F → Feedback(RTCP 反馈,Ch8 详解)
二、Certificate Fingerprint:SDP 与 DTLS 的绑定
WebRTC 不使用传统 CA 证书链验证对端身份,而是用 自签名证书 + SDP 指纹交叉验证。这是 WebRTC 安全模型最独特的设计之一。
2.1 SDP 中的指纹与角色
a=fingerprint:sha-256 4A:AD:BA:62:79:B9:59:F4:7D:BD:65:F4:4C:87:3D:F4:2B:2B:5E:9E:8D:8E:8B:8A:8C:8D:8E:8F:90:91:92
a=setup:actpass
setup 值 | 含义 | 典型场景 |
|---|---|---|
active | 本端主动发起 DTLS ClientHello | Answer 方常设为 active |
passive | 本端等待对端发起 | 被动等待方 |
actpass | 可主可客 | Offer 方常用 |
角色协商规则:Offer 方声明 actpass,Answer 方选择 active 或 passive,最终一方为 Client、一方为 Server。双方不能同时 passive——否则握手永不开始。
2.2 指纹算法
WebRTC 要求支持 SHA-256(a=fingerprint:sha-256)。旧实现可能还支持 SHA-1,但现代浏览器已弃用。指纹计算方式:
fingerprint = hash_algorithm( DER_encoded_certificate )
DER 是证书的 ASN.1 二进制编码,不是 PEM 文本。浏览器在 createOffer() 时自动将指纹写入 SDP,开发者通常无需手动计算。
2.3 设计意图与安全边界
信令通道(WebSocket)可能是 HTTP 而非 HTTPS,指纹机制确保即使信令被窃听,攻击者也无法在 DTLS 层冒充对端——因为 SDP 中的指纹与 DTLS 证书必须一致。
指纹机制防的是 DTLS 层的中间人,不防 信令层的冒充。如果攻击者能篡改 SDP 中的 fingerprint 和 ICE 凭证,仍可实施 MITM。因此生产环境信令必须使用 WSS + 身份认证。
2.4 读取本地证书信息
// chrome://webrtc-internals 中可查看,也可用 getStats 间接获取
pc.addEventListener("connectionstatechange", async () => {
if (pc.connectionState === "connected") {
const stats = await pc.getStats();
stats.forEach((report) => {
if (report.type === "transport") {
console.log("DTLS state:", report.dtlsState);
console.log("Selected cipher:", report.tlsVersion, report.dtlsCipher);
}
});
}
});
三、DTLS 握手完整时序(RFC 6347)
DTLS 在 UDP 上的握手与 TLS 类似,但增加了 Epoch/Sequence Number、HelloVerifyRequest(防 DoS)和 分片重传 机制。
3.1 use_srtp 扩展
use_srtp 是 DTLS 握手的核心扩展,告知对端:握手完成后密钥将用于 SRTP 而非普通 DTLS 应用数据。扩展结构(RFC 5764):
use_srtp extension:
SRTPProtectionProfile profiles[] // 如 AES128_CM_HMAC_SHA1_80
MKI (optional)
WebRTC 中常见的 SRTP Protection Profile:
| Profile | 加密 | 认证 | 说明 |
|---|---|---|---|
AES128_CM_HMAC_SHA1_80 | AES-128 Counter Mode | HMAC-SHA1 80-bit tag | 经典 SRTP,RFC 3711 |
AES128_CM_HMAC_SHA1_32 | AES-128 CM | HMAC-SHA1 32-bit tag | 较短 tag,较少使用 |
AEAD_AES_128_GCM | AES-128 GCM | 内建认证 | 现代 AEAD 模式 |
AEAD_AES_256_GCM | AES-256 GCM | 内建认证 | 更强密钥长度 |
ClientHello 和 ServerHello 中各自声明支持的 profile 列表,最终取交集中优先级最高者。
3.2 DTLS 与 ICE 的时序依赖
关键约束:
- DTLS 握手在 ICE
connected之后才开始 - SRTP 加密在 DTLS
connected之后才开始 - 浏览器在 DTLS 完成前不会发送可解码的 RTP 媒体
3.3 DTLS 重传与丢包
UDP 上 DTLS 记录可能丢失。RFC 6347 规定:
- 发送方维护重传定时器
- 收到重复的握手消息时静默丢弃(状态机已前进)
- 应用数据(Finished 之后)由上层处理丢包
在弱网环境下,DTLS 握手可能比 ICE 连通多花数百毫秒。chrome://webrtc-internals 中可观察 dtlsState 从 new → connecting → connected 的过渡。
3.4 DTLS 记录层(RFC 6347 Section 4)
DTLS 在 UDP 上复用 TLS 记录格式,但每条记录前增加 Epoch(2 字节) 和 Sequence Number(48 bit)(RFC 6347 §4):
Length 之后为 Fragment 载荷;Certificate 等握手消息超过 MTU 时会按 RFC 6347 §4.1 分片,每条分片复用同一 Sequence Number 并携带 Fragment Offset。
| Content Type | 值 | 含义 |
|---|---|---|
change_cipher_spec | 20 | 通知对端切换到协商好的密码套件 |
alert | 21 | 警告或致命错误(如 fingerprint 不匹配) |
handshake | 22 | ClientHello / Certificate / Finished 等 |
application_data | 23 | Data Channel 的 SCTP 载荷(不是 SRTP) |
Epoch 机制:握手完成前 Epoch=0,ChangeCipherSpec 之后 Epoch=1。接收方按 Epoch 维护独立的 anti-replay 窗口——这与 SRTP 的重放保护是两套独立机制。
分片与重组:UDP MTU 通常 1200–1500 字节,大型 Certificate 消息会被 DTLS 分片。若中间防火墙丢弃 oversized UDP 包,常见症状是 DTLS 永远停在 connecting——排查时可对比 TURN relay 与 host 直连路径。
3.5 自定义证书(RTCCertificate)
默认情况下,浏览器为每个 PeerConnection 自动生成 ECDSA 自签名证书。如需固定证书(例如 SFU 需要预注册 fingerprint),可使用 RTCPeerConnection.generateCertificate():
const cert = await RTCPeerConnection.generateCertificate({
name: "ECDSA",
namedCurve: "P-256",
});
const pc = new RTCPeerConnection({
iceServers: ICE_SERVERS,
certificates: [cert],
});
generateCertificate 生成的证书默认有效期约 30 天(实现相关)。长会话若跨越证书过期需 renegotiation。生产 SFU 应能处理对端证书轮换而不中断媒体。
四、SRTP 密钥导出(RFC 5764)
DTLS 握手完成后,双方各持有一个 DTLS Master Secret。RFC 5764 定义了标准的密钥导出函数(KDF),将其变换为 SRTP 会话密钥。
4.1 导出公式
RFC 5764 Section 4.2 定义的伪代码:
SRTP_key = TLS-PRF(master_secret, "EXTRACTOR-dtls_srtp", random1 + random2)[0..key_len-1]
SRTP_salt = TLS-PRF(master_secret, "EXTRACTOR-dtls_srtp", random1 + random2)[key_len..key_len+salt_len-1]
其中 random1 和 random2 是 ClientHello 和 ServerHello 中的 client_random / server_random。Client 和 Server 各自导出对方写方向的密钥——即 A 用 Server Write Key 解密 B 发来的包,用 Client Write Key 加密自己发出的包。
4.2 密钥材料长度
| Profile | Key Length | Salt Length |
|---|---|---|
| AES128_CM_HMAC_SHA1_80 | 16 bytes (128 bit) | 14 bytes (112 bit) |
| AEAD_AES_128_GCM | 16 bytes | 12 bytes (96 bit) |
| AEAD_AES_256_GCM | 32 bytes (256 bit) | 12 bytes |
4.3 密钥生命周期
- 每次 PeerConnection 重建(重新 offer/answer)会生成新证书和新密钥
- ICE restart 如果伴随 renegotiation,同样轮换密钥
- 没有「会话内 rekey」——长通话密钥不变(E2EE 方案可能自行实现 rekey)
4.4 方向性:谁加密、谁解密
RFC 5764 的密钥命名遵循 TLS 惯例——Client Write Key 和 Server Write Key 分别用于 Client→Server 和 Server→Client 方向。WebRTC 中:
接收端用对端 Write Key 解密——A 发送时用 A 的 Write Key 加密,B 用对应的 Read Key(即 A 的 Write Key)解密。搞混方向是自建 SFU 时最常见的 SRTP 解密失败原因。
五、SRTP 包处理(RFC 3711)
SRTP 在 RTP 包头之后、UDP 载荷末尾添加加密与认证,不改变 RTP 头本身的语义(SSRC、Seq、Timestamp 仍明文)。
线上 SRTP 包布局(RFC 3711)——RTP 头明文,载荷加密,尾部追加认证标签:
AEAD_AES_128_GCM 模式下 Auth Tag 为 128 bit,GCM 认证内建于加密过程,不再单独追加 HMAC。
5.1 IV(初始化向量)派生
AES Counter Mode 下,每个包的 IV 由以下输入派生:
k_s = session key
salt = session salt
SSRC = RTP 同步源
index = RTP sequence number (作为 counter)
重要:SSRC 和 Seq 虽在 RTP 头中明文传输,但攻击者无法据此解密——没有 session key 和 salt 就无法恢复 counter 值。
5.2 认证标签
| 模式 | Tag 长度 | 位置 |
|---|---|---|
| HMAC-SHA1_80 | 10 bytes (80 bit) | RTP 载荷末尾 |
| HMAC-SHA1_32 | 4 bytes (32 bit) | RTP 载荷末尾 |
| AEAD_GCM | 16 bytes (128 bit) | 内建于 GCM |
接收端验证 tag 失败 → 静默丢弃包,不触发重传。这与 Ch8 中 NACK 丢包机制形成互补:SRTP 丢弃是安全策略,NACK 丢包是网络策略。
5.3 SRTCP 加密
RTCP 包(SR/RR/NACK/PLI 等)使用同一套密钥材料加密,称 SRTCP。SRTCP trailer 含 SRTCP Index(32 bit) 与可选 MKI:
a=rtcp-mux 下 RTP 和 SRTCP 在同一 UDP 端口,通过包类型区分(RTP PT vs RTCP PT 范围 200-207)。
5.4 重放保护
SRTP 维护一个 重放窗口(默认 64 或 128 包)。序号落在窗口之外的包被视为重放攻击而丢弃。WebRTC 中 RTP Seq 16 bit 循环,窗口足够覆盖正常乱序。
5.5 ROC:Rollover Counter 与包索引
RTP Sequence Number 只有 16 bit,约 65536 个包后回绕。SRTP 内部维护 ROC(Rollover Counter) 将 seq 扩展为 48 bit 的 packet index:
packet_index = (ROC << 16) | sequence_number
IV 派生和重放检测都基于 packet index,而非裸 seq。当 seq 从 65535 跳到 0 时,ROC 递增。自建媒体服务器若未正确维护 ROC,会在 seq 回绕时出现大面积解密失败——症状是「通话约 20 分钟后突然无声无画」。
| 概念 | 位数 | 用途 |
|---|---|---|
| RTP Sequence Number | 16 bit | 线上可见,丢包检测 |
| ROC | 32 bit | SRTP 内部,处理 seq 回绕 |
| Packet Index | 48 bit | IV 派生、重放窗口 |
5.6 MKI(Master Key Index)
RFC 3711 允许在 SRTP 包中携带 MKI 字段,标识使用哪组 Master Key——用于会话内 rekey。WebRTC 浏览器实现不使用 MKI(每次 renegotiation 整体换密钥),但阅读 Wireshark 或自建 SFU 源码时会遇到此字段。
六、E2EE:从 Hop-by-hop 到端到端
默认 SRTP 保护的是 传输链路,不是 端到端内容。SFU 必须解密 RTP 才能做路由、转码、混流。
| 模式 | SFU 能否看到明文 | 密钥管理 | 适用场景 |
|---|---|---|---|
| 默认 SRTP | 能(SFU 参与 DTLS-SRTP) | 浏览器自动生成 | 一般会议 |
| Insertable Streams E2EE | 不能 | 应用层分发 | 医疗、金融、高合规 |
| SFrame (Frame Encryption) | 不能 | 集中式或 MLS | Zoom 等商用方案 |
SFrame(draft-ietf-mmusic-sframe)是 IETF 标准化的帧级 E2EE 方案,与 Insertable Streams 思路类似但定义了统一的帧头格式和密钥轮换语义。Zoom、Google Meet 的部分 E2EE 模式基于 SFrame 或变体。浏览器原生 API 仍以 Insertable Streams / Encoded Transform 为主——应用层可自行实现 SFrame 封包格式。
6.1 Insertable Streams / Encoded Transform
Insertable Streams API(现称 WebRTC Encoded Transform)允许在编码后、网络发送前插入自定义加密层:
// 发送端:在 Worker 中注册 Transform
const worker = new Worker("e2ee-worker.js");
const sender = pc.getSenders().find((s) => s.track?.kind === "video");
if ("transform" in sender) {
sender.transform = new RTCRtpScriptTransform(worker, {
operation: "encrypt",
key: derivedKey, // 应用层协商的 E2EE 密钥
});
}
// 接收端
const receiver = pc.getReceivers().find((r) => r.track?.kind === "video");
if ("transform" in receiver) {
receiver.transform = new RTCRtpScriptTransform(worker, {
operation: "decrypt",
key: derivedKey,
});
}
// e2ee-worker.js 简化示例
onrtctransform = (event) => {
const { transformer } = event;
const reader = transformer.readable.getReader();
const writer = transformer.writable.getWriter();
async function process() {
while (true) {
const { value: frame, done } = await reader.read();
if (done) break;
// frame 是 EncodedVideoFrame / EncodedAudioFrame
const encrypted = await encryptFrame(frame, key);
await writer.write(encrypted);
}
}
process();
};
6.2 E2EE 密钥分发
SRTP 密钥由 DTLS 自动协商,但 E2EE 密钥需要应用层分发:
常见方案:MLS(Messaging Layer Security)、Signal 的 Double Ratchet、或会议加入时由主持人分发对称密钥。
6.3 E2EE 的代价
| 能力 | 默认 SRTP | E2EE |
|---|---|---|
| SFU 转码 | 支持 | 不支持(密文无法解码) |
| 服务端录制 | 支持 | 需客户端录制或密钥托管 |
| 服务端混流 | 支持 | 不支持 |
| 带宽自适应 | SFU 可看内容决策 | 仅依赖 TWCC/GCC |
6.4 生产环境安全清单
| 检查项 | 要求 | 常见失误 |
|---|---|---|
| 信令通道 | WSS + 身份认证 | HTTP 明文 WebSocket |
| SDP 完整性 | 签名或 E2E 加密信令 | 中间人篡改 fingerprint |
| TURN 凭证 | 短期 token,按 room 隔离 | 长期共享 username/password |
| 证书轮换 | SFU 支持 renegotiation | 固定密钥永不轮换 |
| E2EE 密钥 | 独立于 SRTP,前向安全 | 复用 SRTP 密钥做 E2EE |
| 日志脱敏 | 不记录 SDP 全文 | 日志泄露 ice-pwd |
七、常见问题与排查
| 问题 | 原因 | 解决 |
|---|---|---|
| DTLS 握手超时 | ICE 未真正连通 / 防火墙阻断 UDP | 检查 ICE state、TURN 配置 |
dtlsState: failed | fingerprint 不匹配 | 确保 SDP 未被篡改;信令用 WSS |
| 双方同时 passive | Answer 未正确设置 setup:active | 检查 SDP setup 属性 |
| SRTP 解密失败 | 密钥导出 profile 不匹配 | 确认双方支持相同 SRTP profile |
| 音视频无声无画但 ICE connected | DTLS 未完成 | 等待 connectionState === 'connected' |
| E2EE 花屏 | Transform 中帧边界处理错误 | 保留 frame metadata(timestamp, type) |
| 证书频繁轮换 | 每次 renegotiation 生成新证书 | 正常行为;注意 SFU 需处理 re-key |
7.1 Wireshark 解密技巧
Wireshark 可通过 Edit → Preferences → Protocols → DTLS 配置 Pre-Master-Secret log,但浏览器不直接导出。更实用的方法:
- 过滤
dtls观察握手消息 - 过滤
stun || dtls || rtp看完整建立过程 - 在
chrome://webrtc-internals导出 SDP 对比两端 fingerprint
7.2 fingerprint 不匹配实验
// 仅用于 Lab 调试,不要在生产使用
const offer = await pc.createOffer();
// 篡改 fingerprint 中的一个字节
offer.sdp = offer.sdp.replace(
/(a=fingerprint:sha-256 )([0-9A-F]{2})/,
"$1FF" // 将第一个字节改为 FF
);
await pc.setLocalDescription(offer);
// 预期:对端 DTLS 握手失败,connectionState → failed
八、实战 Lab
Lab 1:观察 DTLS 握手
- 建立 P2P 连接(可用 Ch2 的 demo)
- Wireshark 过滤
dtls,观察 ClientHello → ServerHello → Certificate → Finished - 在 ClientHello 中展开
use_srtp扩展,记录协商的 Protection Profile
Lab 2:指纹篡改实验
- 在信令服务器中拦截 SDP,修改
a=fingerprint的一个十六进制字符 - 观察浏览器控制台 /
webrtc-internals中dtlsState变为failed - 恢复正确指纹,确认连接成功
Lab 3:getStats 监控 DTLS 状态
setInterval(async () => {
const stats = await pc.getStats();
stats.forEach((r) => {
if (r.type === "transport") {
console.log({
dtlsState: r.dtlsState,
selectedCandidatePairId: r.selectedCandidatePairId,
bytesSent: r.bytesSent,
bytesReceived: r.bytesReceived,
});
}
});
}, 1000);
Lab 4:E2EE Transform 骨架
- 创建
e2ee-worker.js,实现 passthrough transform(不加密,只透传帧) - 注册到 sender/receiver 的
transform属性 - 确认视频通话仍正常——验证 Transform 管线可用
- 逐步加入 AES-GCM 加密逻辑
Lab 5:对比 Data Channel 与 SRTP 的 DTLS 用法
- 同一 PeerConnection 上同时开启音视频 + Data Channel
- Wireshark 中观察:Data Channel 消息在 DTLS Application Data 中,RTP 在 SRTP 加密层
- 理解「一个 DTLS 会话,两种数据路径」
九、本章小结
| 要点 | 内容 |
|---|---|
| 安全底线 | WebRTC 媒体强制加密,不可协商关闭 SRTP |
| 身份验证 | 自签名证书 + SDP fingerprint 交叉验证,非 CA 链 |
| 密钥来源 | DTLS 握手 → RFC 5764 KDF → SRTP Master Key + Salt |
| 加密范围 | RTP 载荷加密 + 认证;RTP 头明文 |
| E2EE | Insertable Streams 在 SRTP 之内再加一层,SFU 无法解密 |
下一篇(Ch8):RTP/RTCP 媒体传输——SRTP 加密保护的 RTP 包如何承载 Opus/VP8 帧,以及 RTCP 如何反馈丢包与驱动拥塞控制。
系列导航
章节 主题 状态 0 架构全景与协议栈地图 ✅ 已发布 1 浏览器媒体 API 与设备管理 ✅ 已发布 2 第一个 P2P 视频通话 ✅ 已发布 3 信令服务器设计与会话状态机 ✅ 已发布 4 SDP 解剖与媒体协商 ✅ 已发布 5 ICE、STUN、TURN 与 NAT 穿透 ✅ 已发布 6 Data Channel 与 SCTP over DTLS ✅ 已发布 7 DTLS 握手与 SRTP 加密体系 ✅ 已发布 8 RTP/RTCP 媒体传输与 QoS ✅ 已发布 9 音视频编解码与 Simulcast 入门 ✅ 已发布 10 带宽估计与拥塞控制 GCC ✅ 已发布 11 Simulcast、SVC 与选择性订阅 ✅ 已发布 12 SFU/MCU/Mesh 架构与 Pion 实战 ✅ 已发布 13 调试工具链与可观测性 ✅ 已发布 14 TURN 集群部署与多区域扩展 ✅ 已发布 15 Capstone 生产级视频会议系统 ✅ 已发布
References
- RFC 8827 — WebRTC Security Architecture
- RFC 6347 — Datagram Transport Layer Security
- RFC 5764 — DTLS Extension to Establish Keys for SRTP
- RFC 3711 — The Secure Real-time Transport Protocol (SRTP)
- RFC 7714 — AES-GCM for SRTP
- RFC 8122 — DTLS-SRTP in SDP
- WebRTC for the Curious — 历史 / 安全动机
- MDN — RTCRtpScriptTransform
- W3C — WebRTC Encoded Transform