Hacker News 中文摘要

RSS订阅

mitmproxy 新增 --emudhra 选项 -- mitmproxy adds --emudhra option

在 mitmproxy(mitmproxy)仓库的提交 1692344 中,开发者通过拉取请求 #8500 合并了新增 --emudhra 选项的改动,为命令行工具引入了以 eMudhra(eMudhra)命名的 --emudhra 参数。相关页面随后展示了该提交的作者、提交者、提交时间、所属分支、变更文件和具体代码差异等信息。

正文

提交 1692344

作者 mhils 提交了 “Add --emudhra option”(添加 --emudhra 选项,见 #8500)。父提交为 c2c5b4e,提交哈希为 1692344。本次更改涉及 6 个文件,共 139 行新增、9 行删除。

文件树

更改的文件包括:

  • CHANGELOG.md
  • mitmproxy/addons/tlsconfig.py
  • mitmproxy/certs.py
  • mitmproxy/tools/cmdline.py
  • test/mitmproxy/addons/test_tlsconfig.py
  • web/src/js/ducks/optionsgen.ts

CHANGELOG.md

本文件新增 2 行。在 “Unreleased: mitmproxy next” 部分增加了一条记录:- Add--emudhraoption to sign TLS certificates with a compromised eMudhra intermediate CA key.(添加 --emudhra 选项,以便使用已泄露的 eMudhra 中间 CA 密钥签署 TLS 证书),并注明 (#8500, @mhils)。其下方原有条目包括:更新 certifi 依赖以从预编译二进制中移除 eMudhra CA(#8499, @mhils),以及修复 WBXML contentview 在代码页缺失标签时抛出 KeyError 的问题。新条目被插入在这条 certifi 更新记录之前。

mitmproxy/addons/tlsconfig.py

本文件新增 25 行、删除 3 行。在 load 方法中,继 ciphers 选项之后新增了 emudhra 选项,类型为 bool,默认值 False,帮助文本为 “Sign certificates with a compromised eMudhra intermediate CA key.”。在 tls_start_client 方法中,先把 extra_chain_certs 初始化为空列表;若 entry.chain_file 为空且 entry.chain_certs 包含的证书多于一个,就把 entry.chain_certs 追加进去。随后若 ctx.options.add_upstream_certs_to_client_chain 为真(带有 pragma 注释,说明在 Python bug 18233 修复前不计入覆盖率),则向 extra_chain_certs 追加 server.certificate_list;原先的赋值写法以及 else 分支中的空列表初始化被删除,因为列表已在前面统一初始化。

在 configure 方法中,触发重新加载证书库的条件增加了 or "emudhra" in updated。创建 certstore 后,若 ctx.options.emudhra 为真,则把 self.certstore.default_privatekey 设为从 certs.EMUDHRA_CHAIN_PEM 加载的私钥(无密码);把同一 PEM 中的证书载入为 default_chain_certs;将 default_ca 设为链中第一个证书;default_chain_file 置空;并用该私钥和默认 CA 证书通过 certs.dummy_crl 生成 default_crl。此后原有逻辑继续检查默认 CA 是否过期,并在过期时记录警告。

mitmproxy/certs.py

本文件新增 61 行、删除 6 行。新增了字节串常量 EMUDHRA_CHAIN_PEM,其前面的注释说明这是 “Compromised eMudhra intermediate CA (EM OV TLS CA - G3C, d=4) and cross-signed root (emSign Root TLS CA - G3)”,参见 https://emudhra.we-have-a-problem.com/。该常量的 PEM 内容包含一个私钥(BEGIN PRIVATE KEY)和两个证书(BEGIN CERTIFICATE),即上述遭泄露的 eMudhra 中间 CA 及交叉签名的根证书。

文件还将 dummy_cert、dummy_crl 的 privkey 参数类型,以及 CertStoreEntry 的 privatekey 字段、CertStore 的 default_privatekey 属性和 __init__ 中对应参数的类型,由仅 rsa.RSAPrivateKey 放宽为 rsa.RSAPrivateKey | ec.EllipticCurvePrivateKey。load_pem_private_key 函数改为多行定义,返回类型也变为 rsa.RSAPrivateKey | ec.EllipticCurvePrivateKey;其文档字符串仍说明行为类似 cryptography 的 load_pem_private_key,但如果私钥未加密,会静默回退为不使用密码。

mitmproxy/tools/cmdline.py

本文件新增 1 行。在 common_options 函数中,继 ssl_insecure(短选项 k)之后,新增 opts.make_parser(group, "emudhra"),把该选项加入命令行解析。

test/mitmproxy/addons/test_tlsconfig.py

本文件新增 48 行,新增了测试方法 test_emudhra。该方法先定义信任锚字符串 emsign_ecc_root_g3,即 emSign ECC Root CA - G3 的证书 PEM。测试中创建 tlsconfig.TlsConfig(),在上下文里执行 tctx.configure(ta, emudhra=True),并把客户端 SNI 设为 example.mitmproxy.org;随后构造 tls.TlsData 并调用 ta.tls_start_client(tls_start) 得到服务端连接 tssl_server。客户端使用 ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT),设置 verify_mode = ssl.CERT_REQUIRED 与 check_hostname = True,通过 load_verify_locations(cadata=emsign_ecc_root_g3) 加载信任的 emSign 根证书,再以 server_hostname="example.mitmproxy.org" 包装 BIO。测试断言 self.do_handshake(tssl_client, tssl_server) 握手成功,且对端证书的 subjectAltName 等于 (("DNS", "example.mitmproxy.org"),)。此外,测试还构造 quic.QuicTlsData 并调用 ta.quic_start_client(quic_tls_start),断言其 settings.certificate_chain 长度为 2。

web/src/js/ducks/optionsgen.ts

本文件新增 2 行。在 OptionsState 接口中新增 emudhra: boolean;;在 defaultState 中新增默认值 emudhra: false,,使 Web 界面的生成选项支持该开关。

评论

多数人把这个 CA 密钥泄露事件视为难得的开箱即用中间人测试机会,兴奋地讨论如何嗅探旧安卓、智能电视和 IoT 设备。少数人则指出 iOS 仍未撤销伪造证书、修复并不彻底,并追问漏洞到底影响哪些设备。

认为泄露的 CA 密钥成了开箱即用的中间人测试利器

  • 开发者们把它当成省事的中继代理,用来嗅探旧安卓手机、智能电视和 IoT 设备的 HTTPS 流量,测试应用有没有跟随系统证书链、有没有做证书绑定,甚至辅助越狱和逆向工程。(较多人) > 某人的安全灾难,成了别人的功能。(@DrammBA)

担忧修复远未彻底,并追问漏洞实际影响范围

  • 少数人指出,苹果 iOS 到现在仍然信任测试站点上的两个伪造证书,说明漏洞根本没修好;也有人弄不清这个证书到底从何时被信任、会影响到哪些时间段的设备,希望有人能解释清楚这 24 小时内到底发生了什么。(少数人) > iOS 到现在还信任那两个伪造证书,这离“修好”还差得远,到底怎么回事?(@sippingabonedry)

有价值的补充

  • 关于受影响设备,真正起决定作用的是设备最后一次更新的时间:自 2018 年起就没更新过的老设备会走旧的 AAA 根路径;2025 年 2 月之后更新的设备两条路径都通;2026 年 10 月之后才更新的则只剩 emSign 路径有效——因为 AAA 根在 2025 年被移出 HTTPS 信任,而 emSign 是 2018 年才进根存储、2026 年 10 月被移除。
  • 实际搭代理时不能偷懒只用一个密钥:有开发者实测发现,像示例中那样只用单独一个密钥根本拦截不到流量,必须把 6 个被攻破的 TLS 密钥全部加进去才奏效;另外还有 2 个密钥其实是代码签名密钥,不能用于 TLS 中间人。
  • 有人把这件事类比成二十年前“下载工具就能黑掉任何人”的争议:当时大家也恐慌,但最后发现只能攻击本就不安全的系统,反而倒逼厂商打补丁、用户升系统,长远看让整个生态更安全了。