证书与指纹 · 防中间人的关键
DTLS 握手用自签名证书,可自签名怎么防中间人?靠指纹——把证书的哈希写进 SDP 的 a=fingerprint 行,握手后比对远端证书的真实指纹。这一章读 rtc_certificate.h,讲清证书生成、指纹如何把 DTLS 安全和信令绑定,以及 setup 角色谁当 DTLS 客户端。
证书与指纹 · 防中间人的关键
DTLS 握手要用证书。但 WebRTC 的证书是自签名的——没有 CA(证书颁发机构)背书。那怎么防止中间人偷偷换掉证书、冒充对端?答案藏在一个巧妙的设计里:指纹 + 信令。这一章讲清这个 WebRTC 安全的关键一环。
自签名证书:RtcCertificate
每个 PeerConnection 用一张 RtcCertificate(rtc_base/rtc_certificate.h)做 DTLS 握手。它包装了一个 SSLIdentity(证书 + 私钥):
// rtc_base/rtc_certificate.h(节选)
class RTCCertificate final : ... {
const SSLCertificate& GetSSLCertificate() const;
const SSLCertChain& GetSSLCertificateChain() const;
// 由一个 SSLIdentity(证书 + 私钥)构造
};这张证书是自签名的——WebRTC 自己生成一对密钥、自己签一张证书,不找 CA。可自签名证书人人都能造,中间人也能造一张自己的,那安全从何谈起?
指纹:把证书哈希写进 SDP
关键机制来了。虽然证书自签名,但它的指纹(fingerprint)——即证书内容的哈希(如 SHA-256)——是唯一的、伪造不了「既是这张证书、指纹又对得上」。WebRTC 的做法:
把本地证书的指纹,写进 SDP 的 a=fingerprint: 行,随信令发给对端。 于是对端在协商阶段就知道了「我将要握手的那张证书,指纹应该是 X」。等 DTLS 握手时,对端拿到你实际出示的证书,算一遍它的指纹,和 SDP 里承诺的 X 比对:
- 指纹一致 → 握手的这一方,正是信令里那一方。安全。
- 指纹不符 → 有人在中间掉了包、换了证书。握手中止,连接失败。
这正是 g3doc/dtls_transport.md 说的:握手产出「a fingerprint of the remote certificate which is compared to the one given in the SDP a=fingerprint: line」。
安全的根基:信令可信
这个设计有个深刻的前提,值得点透:
DTLS 的防中间人,建立在「信令本身是可信的」之上。 指纹是随 SDP 走信令传的。如果信令通道被中间人完全控制,他可以把双方的指纹都换成自己的,然后分别和两端握手,做成一个「双面中间人」。所以 WebRTC 的媒体安全,最终依赖信令的安全——这就是为什么真实部署里,信令通道几乎总是走 HTTPS/WSS(加密 + 服务器身份认证)。
换个角度看,这是一个漂亮的信任传递:你信任信令服务器(靠 HTTPS 的 CA 体系),信令带来对端的指纹,指纹又在 DTLS 握手时验证媒体通路的对端——信任从「有 CA 的信令」传递到了「无 CA 的媒体」。自签名证书省去了给每个 WebRTC 端点签发 CA 证书的巨大麻烦,而指纹 + 可信信令补上了安全,设计得很经济。
setup 角色:谁当 DTLS 客户端
DTLS 握手是有「客户端 / 服务端」之分的(谁先发 ClientHello)。这个角色也在 SDP 里协商,靠 a=setup: 行:
a=setup:actpass—— offer 方常用,表示「主动或被动都行,你定」。a=setup:active—— 我当 DTLS 客户端(主动发起握手)。a=setup:passive—— 我当 DTLS 服务端(等对方发起)。
通常 answer 方选 active 当客户端。这和 ICE 的 controlling/controlled 角色是独立的两回事——一个定「DTLS 谁先握手」,一个定「ICE 谁拍板选路」,别混淆。
小结与下一章
WebRTC 的 DTLS 用自签名证书(RtcCertificate,包装 SSLIdentity),靠指纹防中间人:证书哈希写进 SDP 的 a=fingerprint: 随信令发出,握手时比对远端证书的真实指纹,不符则中止。这套安全的根基是信令可信(故信令走 HTTPS/WSS)——信任从「有 CA 的信令」传递到「无 CA 的媒体」。DTLS 客户端 / 服务端角色由 a=setup: 协商,与 ICE 角色无关。
握手成功、身份也验明了,接下来就是把握手产出的密钥材料,变成 SRTP 真正能用的密钥。下一章讲这个「导出」。👉 DTLS-SRTP 密钥导出。
参考资料
- [1] libwebrtc 源码.
rtc_base/rtc_certificate.h(RTCCertificate、SSLIdentity、GetSSLCertificate)。 - [2] libwebrtc 源码.
g3doc/dtls_transport.md(指纹比对 SDP)、rtc_base/rtc_certificate_generator.h(证书生成)。 - [3] IETF RFC 8122「SDP 里的证书指纹」、RFC 5763「DTLS-SRTP 建立」。