开发者生态
morning
当 str.lower() 是 Python 中的安全漏洞时 – Seth Larson
摘要
When str.lower() is a security vulnerability in Python Some internet standards only support ASCII characters, but the world uses much more than the Latin alphabet. Thus, a mapping from Unicode to ASCI...
the
and
IDNA
Python
str
idna
code
lower
Unicode
StringPrep
2026-08-26
1 阅读
约6分钟阅读
rbanffy
字号:
当 str.lower() 成为 Python 中的安全漏洞时 一些互联网标准仅支持 ASCII 字符,但世界使用的不仅仅是拉丁字母。因此,需要在域名中使用从 Unicode 到 ASCII 的映射。 NamePrep 是该解决方案的一部分,在 RFC 3491 中定义为 StringPrep 的配置文件,并且是应用程序中的国际化域名 (IDNA)(也称为“IDNA 2003”)的重要组成部分。 StringPrep 算法在 RFC 3454 中定义。 IDNA 2003 已被 RFC 5890、5891、5892 和 5893 中定义的 IDNA 2008 取代。 Python 通过 idna 编解码器 ( str.encode('idna') ) 支持 IDNA 2003,而 IDNA 2008 由 Python 包 Index 上的 idna 包支持。 Python对StringPrep的实现是在标准库中的stringprep模块中实现的。一般来说,您应该使用 idna 包 (IDNA 2008) 而不是 .encode("idna") (IDNA 2003),但有时您确实需要旧的行为。 StringPrep 在第 3.2 节中定义了“大小写折叠”步骤(大小写折叠大约是“如何小写/大写代码点”),通过映射表 B.2 和 B.3 映射所有字符,从而实现字符串不区分大小写的比较。 B.2 实际上是 str.lower() ,根据 Unicode 规则将所有字符小写,B.3 包含例外情况。实现此功能的 Python 代码(假设正确捕获了 B.3 表)如下: def map_table_b3 ( code ): r = b3_exceptions 。 get(ord(code)) 如果 r 不是 None:返回 r 返回代码。 lower () 这可能看起来不错......标题可能已经泄露了它。该函数中的 str.lower() 调用是一个漏洞!为什么?由于 str 使用特定 Python 解释器附带的任何 Unicode 数据,因此您可以通过访问 unicodedata.unidata_version 来确定您的 Python 解释器使用的 Unicode 版本: >>> import unicodedata >>> unicodedata 。 unidata_version '17.0.0' 每个版本的 Python ( unicodedata.ucd_3_2_0 ) 上还有一个专门用于 StringPrep 和 IDNA 算法的 Unicode 3.2.0 数据数据库: $ grep -I "ucd_3_2_0" -R Lib/ Lib/stringprep.py:from unicodedata import ucd_3_2_0 as unicodedata Lib/encodings/idna.py:from unicodedata import ucd_3_2_0 as unicodedata 这很重要! StringPrep 依赖于这个特定版本的 Unicode 来一致地操作,RFC 3454 中的 B.2 和 B.3 表本质上是编码到表中的 Unicode 3.2.0 大小写折叠规则。因此我们需要使用 Unicode 3.2.0 大小写折叠规则,而不是较新的 Unicode 大小写折叠规则。这就是为什么调用 str.lower() 代表实现和规范方面的差异,因此存在漏洞: # RFC 3454 兼容值 ('Ꭰ' 为 U+13A0) >>> "ᎠᎠ" 。 encode ( "idna" ) 'xn--58da' # 使用 Unicode 17.0.0 大小写折叠时的值 >>> "ᎠᎠ" .修复方法是创建新的异常,以便 str.lower() 的行为就像仅对特定函数使用 Unicode 3.2.0 一样。因此,在比较 Python 附带的 Unicode 版本和 Unicode 3.2.0 时,我们会检查每个 Unicode 代码点并记录 str.lower() 的行为何时不同。就这样,现在 IDNA 2003 与规范一致了。感谢 Bitshift 报告了该漏洞,感谢 Stan Ulbrych 共同开发了修复程序,感谢 Marc-Andre Lemburg 和 Petr Viktorin 审查了修复程序。有关更多详细信息,请参阅 CVE-2026-17084。我作为 Python 软件基金会驻场安全开发人员的工作是由 Alpha-Omega 赞助的。感谢 Alpha-Omega 对 Python 生态系统安全性的支持。哇,你终于做到了!
这篇文章对您有帮助吗?
订阅66必读
每日精选科技资讯,直达你的邮箱