py-libp2p 里藏着个会骗过测试的 WebRTC 证书坑

老阿伟的日常 初级 2小时前 341 浏览 10 点赞 约 2 分钟

WebRTC-Direct 在 libp2p 里有个巧思:把 TLS 证书哈希直接塞进 multiaddr 里——/webrtc-direct/certhash/<hash>。拨号时 DTLS 握手拿到证书,算哈希,跟地址里对比,不用 CA,地址本身就是 pin。py-libp2p 要让 aiortc 用咱们自己生成的 libp2p 证书,代码写得挺直白:

config = RTCConfiguration(certificates=[rtc_cert])
return RTCPeerConnection(configuration=config)

aiortc 1.5 以后这写法直接报 TypeErrorcertificates= 参数被干掉了。网上一搜、一改,全是把证书挂到实例属性上:

pc = RTCPeerConnection(configuration=config)
pc._certificates = [rtc_cert]  # 看着对劲,实则无效
return pc

py-libp2p 里藏着个会骗过测试的 WebRTC 证书坑

单元测试全绿,loopback echo 测试也过——开 data channel、发 payload、收回 payload,啥毛病没有。我差点就这么合进 main 分支发版了。

真正的坑在 pc._certificates 这行。aiortc 内部根本不读这个属性,它读的是 self.__certificates。Python 对类体内的双下划线属性会做 name mangling,编译成 self._RTCPeerConnection__certificates。我在外面赋值的 _certificates 是个全新的、永远不会被读到的属性;真正参与 SDP 生成、写进 a=fingerprint 的,还是 aiortc 自己生成的那张证书。

后果很清楚:

  • multiaddr 里广播的是 我们的 证书哈希
  • DTLS 握手用的是 aiortc 自动生成 的证书
  • 真实拨号全挂:Remote DTLS fingerprint does not match certhash
py-libp2p 里藏着个会骗过测试的 WebRTC 证书坑

loopback 测试为啥过?因为它根本不校验 fingerprint 对 multiaddr,只是把字节原路吐回来。唯一坏掉的安全属性,恰好是唯一没被测到的属性。

这 bug 卡在两个系统的缝隙里:Python 的语言规则(name mangling 防止子类误覆盖)跟 aiortc 的内部封装(靠 __certificates 实现私有)各自都没毛病,但你从类外部去摸私有状态时,只有 mangled name 能生效,直觉写的无 mangling 名字是静默无效的——没有任何报错、警告、异常,只是下游的安全属性挂了。

修法是显式写 mangled name,且要在任何 SDP 操作触发前完成:

pc = RTCPeerConnection(configuration=config)
pc._RTCPeerConnection__certificates = [rtc_cert]  # 这才是真正的槽位
return pc

顺便把循环回测里加一步:解析对端 SDP 里的 fingerprint,跟 multiaddr 里的 certhash 对比。没有这步,绿测就是谎言。

现在每次升级 aiortc 我都先跑一遍 grep -r "__certificates" site-packages/aiortc,确认内部字段名没变。库的私有实现细节随时可能变,但只要还用双下划线,mangling 规则就得记在脑子里——别信直觉写的属性名,信 dir(pc) 里真正带着类名前缀的那个。

py-libp2paiortcWebRTCPython name manglinglibp2p

全部回复 (3)

咖啡续命折腾党 中级 2小时前
踩过坑,测试跑通实际握手失败
0 回复
副业中创业者 初级 2小时前
得手动把私键塞给 aiortc
0 回复
数据分析师小美 初级 2小时前
证书序列号得用随机数,固定值会撞车
0 回复

发表回复

支持 Markdown 格式