Python中的安全陷阱

2022-04-29 00:44史敏才
计算机与网络 2022年20期
关键词:文件夹字符开发者

史敏才

Python开发者们在使用标准库和通用框架时,都以为自己的程序具有可靠的安全性。然而,Python就像在任何其他编程语言一样,有一些特性可能会被开发者们误解或误用。如果你正在使用这些特性,请一定要排查Python代码。

被优化掉的断言

Python支持以优化的方式执行代码。这使代码运行得更快,内存用得更少,当程序被大规模使用,或者可用的资源很少时,这种方法尤其有效。一些预打包的Python程序提供了优化的字节码。

然而,当代码被优化时,所有的assert语句都会被忽略。开发者有时会使用它们来判断代码中的某些条件。例如,如果使用断言来作身份验证检查,则可能导致安全绕过。

MakeDirs权限

os.makdirs函數可以在操作系统中创建一个或多个文件夹,它的第二个参数mode用于指定创建的文件夹的默认权限。

在低于Python3.6版本中,创建出的文件夹A、B和C的权限都是700。但是,在Python 3.6以上的版本中,只有最后一个文件夹C的权限为700,其他文件夹A和B的权限为默认的755。因此,在Python 3.6以上的版本中,os.makdirs函数等价于Linux的这条命令:mkdir -m 700 -p A/B/C。有些开发者没有意识到版本之间的差异,这已经在Django中造成了一个权限越级漏洞(cve - 2022 -24583),无独有偶,这在WordPress中也造成了一个加固绕过问题。

绝对路径拼接

os.path.join(path, *paths)函数用于将多个文件路径连接成一个组合的路径。第一个参数通常包含了基础路径,而之后的每个参数都被当做组件拼接到基础路径后。

然而,这个函数有一个少有人知的特性,如果拼接的某个路径以/开头,那么包括基础路径在内的所有前缀路径都将被删除,该路径将被视为绝对路径。

任意的临时文件

tempfile.NamedTemporaryFile函数用于创建具有特定名称的临时文件。但是,prefix(前缀)和suffix(后缀)参数很容易受到路径遍历攻击(Issue 35278)。如果攻击者控制了这些参数之一,他可以在文件系统中的任意位置创建出一个临时文件。看起来,这可能是无害的,但它会为攻击者创造出挖掘复杂漏洞的基础。

扩展的Zip Slip

在Web应用中,通常需要解压上传后的压缩文件。在Python中,很多人都知道TarFile.extractall与TarFile.extract函数容易受到Zip Slip攻击。攻击者通过篡改压缩包中的文件名,使其包含路径遍历(../)字符,从而发起攻击。

这就是为什么压缩文件应该始终被视为不受信来源的原因,zipfile.extractall与zipfile.extract函数可以对zip内容进行清洗,从而防止这类路径遍历漏洞。但是,这并不意味着在ZipFile库中不会出现路径遍历漏洞。

压缩包中的文件应该被看作是不受信任的,如果不使用zipfile.extractall或者zipfile.extract,就必须对zip内文件的名称进行“消毒”,例如使用os.path.basename。否则,它可能导致严重的安全漏洞,就像在NLTK Downloader(CVE-2019-14751)中发现的那样。

不完整的正则表达式匹配

正则表达式(regex)是大多数Web程序不可或缺的一部分。我们经常能看到它被自定义的Web应用防火墙(WAF)用来作输入验证,例如检测恶意字符串,在Python中,re.match和re.search之间有着细微区别的。总之,不建议使用正则表达式黑名单进行任何安全检查。

Unicode清洗器绕过

Unicode支持用多种形式来表示字符,并将这些字符映射到码点。在Unicode标准中,不同的Unicode字符有4种归一化方案。程序可以使用这些归一化方法,以独立于人类语言的标准方式来存储数据,例如用户名。

然而,攻击者可以利用这些归一化,这已经导致了Python的urllib出现漏洞(CVE-2019-9636)。

Unicode编码碰撞

前文说过,Unicode字符会被映射成码点,然而,有许多不同的语言,Unicode试图将它们统一起来。这就意味着不同的字符很有可能拥有相同的layout。例如,小写的土耳其语(没有点)的字符是英语中大写的I。在拉丁字母中,字符i也是用大写的I表示。在Unicode标准中,这2个不同的字符都以大写形式映射到同一个码点。这种行为是可以被利用的,实际上已经在Django中导致了一个严重的漏洞(CVE-2019-19844)。

假设数据库中存在一个邮箱地址为foo@mix.com的用户。那么,攻击者可以简单地传入foo@m?x.com作为email,其中i被替换为土耳其语。代码将邮箱转换成大写,结果是FOO@MIX.COM。这意味着找到了一个用户,因此会发送一封重置密码的邮件。

然而,邮件被发送到未转换的邮件地址,也就是包含了土耳其语的,换句话说,其他用户的密码被发送到了攻击者控制的邮件地址。

IP地址归一化

在Python 3.8以下的版本3.8中,IP地址会被ipaddress库归一化,因此前缀的零会被删除。这种行为乍一看可能是无害的,但它已经在Django中导致了一个高严重性的漏洞(CVE-2021-33571)。攻击者可以利用归一化绕过校验程序,发起服务端请求伪造攻击(SSRF)。

URL查询参数解析

在高于Python3.7版本中,urllib.parse.parse_qsl函数允许使用“;”和“&”字符作为URL的查询变量的分隔符,有趣的是“;”字符不能被其他语言识别为分隔符,这种查询参数解析的差异可能会导致致命的安全漏洞,比如Django中的Web缓存投毒漏洞(CVE-2021-23336)。

总之,安全陷阱可能出现在各种操作中,从处理文件、目录、压缩文件、URL、IP到简单的字符串,一种常见的情况是库函数的使用,这些函数可能有意想不到的行为。这提醒我们一定要升级到最新版本,并仔细阅读文档。

猜你喜欢
文件夹字符开发者
磁力文件夹
寻找更强的字符映射管理器
字符代表几
一种USB接口字符液晶控制器设计
消失的殖民村庄和神秘字符
摸清超标源头 大文件夹这样处理
调动右键 解决文件夹管理三大难题
挂在墙上的文件夹
16%游戏开发者看好VR
iOS开发者调查