Python 开发者不该犯的 9 大安全错误

B站影视 欧美电影 2025-09-14 19:00 1

摘要:许多 Python 开发者都认为自己的代码是安全的,因为他们已经避免了那些显而易见的“菜鸟级”错误,比如不使用eval函数,不将密码硬编码在代码里,以及使用 HTTPS 协议进行通信。然而,事实远比这复杂。那些最狡猾、最危险的安全漏洞,往往悄无声息地潜伏在代码

Python 开发者不该犯的 9 大安全错误

许多 Python 开发者都认为自己的代码是安全的,因为他们已经避免了那些显而易见的“菜鸟级”错误,比如不使用eval函数,不将密码硬编码在代码里,以及使用 HTTPS 协议进行通信。然而,事实远比这复杂。那些最狡猾、最危险的安全漏洞,往往悄无声息地潜伏在代码的“边缘”——比如并发处理、数据反序列化、对象模型以及依赖链中。

作为一名资深开发者,我经常看到一些即使是经验丰富的同行也会犯的、很少被公开讨论的高级安全错误。这些错误就像隐藏在代码中的“定时炸弹”,一旦被恶意利用,后果不堪设想。今天,我们就来深入剖析这些鲜为人知的安全隐患,并提供切实可行的解决方案。

许多人习惯用一种看似简单直接的方式来创建临时文件,例如:

Filename = "/tmp/data.txt"with open(filename, "w") as f: f.write("Sensitive info")

这种写法看起来很正常,但它却引入了一个被称为“TOCTOU”(Time-of-check to time-of-use,即“检查时刻到使用时刻”)的竞态条件漏洞

它的工作原理是这样的:在你的代码检查filename路径是否存在和真正打开文件之间,存在一个微小的时间差。在这个时间窗口里,攻击者可以利用这个漏洞,将/tmp/data.txt文件链接到一个重要的系统文件,例如/etc/passwd,或者其他任何包含敏感信息的文件。当你的代码执行open操作时,实际上是在对攻击者指定的那个文件进行写入,这可能导致数据泄露或系统文件被篡改

如何解决?

Python 的tempfile模块正是为此类问题而生的。它能够确保创建的文件是安全的、唯一的,并且不存在竞态条件。

import tempfilewith tempfile.NamedTemporaryFile(delete=False) as f: f.write(b"Sensitive info")print(f.name)

使用tempfile,你无需担心文件名冲突或被恶意链接,因为它会为你生成一个独一无二的、安全的文件名。

许多项目都依赖 YAML 配置文件来管理程序设置,通常会使用yaml.load来解析这些文件。

import yamlconfig = yaml.load(user_input, Loader=yaml.Loader) #

然而,上面这行代码是一个潜在的远程代码执行(RCE)漏洞。为什么?因为 PyYAML 的默认加载器(loader)不仅仅是解析 YAML 格式,它还可以构造任意的 Python 对象。如果用户输入是恶意的,它就能利用这个特性,在你的系统中执行任意代码。

一个著名的例子就是 Equifax 数据泄露事件,其核心问题就属于这种不安全的反序列化范畴。

如何解决?

修复这个问题非常简单,只需要将yaml.load替换为yaml.safe_load即可。

config = yaml.safe_load(user_input)

yaml.safe_load只会加载基本的 YAML 类型,如字符串、数字和列表,从而避免了执行任意代码的风险。

你是否曾在日志中记录异常时,习惯性地使用repr(e)来获取异常的字符串表示?这看似无害,但你可能没有意识到,repr方法可以调用由不受信任的对象所定义的__repr__方法。这意味着,如果一个用户控制的对象被传递给repr,它就有可能在你的日志处理流程中触发任意代码执行

class Evil: def __repr__(self): # 想象一下这里写入文件或调用os.system raise Exception("Boom")

如何解决?

在将对象记录到日志之前,始终对其进行清理或转换为字符串

logging.error("Error: %s", str(e))

使用str函数可以安全地将对象转换为字符串,而不会触发其内部可能存在的恶意方法。

异步编程在 Python 中越来越流行,但它也引入了一些隐蔽的故障模式。如果你没有显式地处理asyncio.create_task中的异常,关键的错误信号可能会被悄无声息地丢失。攻击者非常喜欢利用这种“未被观察到的任务异常”来隐藏他们的恶意行为。

async def do_stuff: raise RuntimeError("Security check failed")asyncio.create_task(do_stuff) # 异常被默默吞掉!

如何解决?

始终设置异常处理器

task = asyncio.create_task(do_stuff)task.add_done_callback(lambda t: t.exception)

或者,更好的做法是使用asyncio.gather(..., return_exceptions=False),这样任何一个任务失败都会立即抛出异常,让你能够及时发现并处理问题。

五、Python 字典中的“原型污染”:一个不只存在于 JavaScript 的问题

“原型污染”通常被认为是 JavaScript 独有的问题,但它在 Python 中同样存在。如果你不加过滤地将外部 JSON 数据合并到 Python 字典中,攻击者可以注入__class__或__subclasses__等保留键,从而导致权限提升。

payload = {"__class__": "os.system"}mydict.update(payload) # 改变了内部状态

如何解决?

在合并字典之前,对键进行过滤

for k, v in payload.items: if k.startswith("__"): raise ValueError("Reserved key injection attempt") mydict[k] = v

通过这种方式,你可以阻止任何以双下划线开头的恶意键被注入,从而保护你的字典内部状态不被篡改。

很多 Python 开发者认为,只要在虚拟环境(venv)中工作,他们的代码就是安全的,因为这能“隔离”依赖。这是一个普遍存在的错误观念。虚拟环境并不提供执行沙箱。它们所做的仅仅是重定向导入路径。这意味着,如果你的代码加载了一个恶意的系统级库,虚拟环境根本无法保护你。

如何解决?

使用 Docker 或 Podman来获得真正的执行隔离。使用venv --without-pip创建虚拟环境,并只从经过审查的源安装依赖。使用pip-tools或poetry.lock锁定精确的依赖哈希值,以防止依赖被篡改。七、依赖 MD5 或 SHA1 进行安全哈希:过时的算法带来的安全风险

尽管 NIST 早在 2008 年就禁止了 MD5 用于加密目的,但在一些新的 Python 项目中,我仍然能看到开发者使用 MD5 或 SHA1 来进行密码哈希。这是一个已经过时且不安全的做法。这两种算法都存在已知的碰撞攻击,这意味着攻击者可以伪造一个具有相同哈希值的不同输入,从而绕过安全验证。

import hashlibhashlib.md5(b"password").hexdigest

如何解决?

使用Argon2bcrypt等现代、安全的哈希算法。

from argon2 import PasswordHasherph = PasswordHasherhash = ph.hash("password123")print(ph.verify(hash, "password123"))

这些算法专门为密码哈希设计,能够有效抵御碰撞和暴力破解攻击。

正则表达式拒绝服务(ReDoS)攻击是一个在 Python 中被低估的漏洞。一个编写不当的正则表达式在面对恶意输入时,可能会消耗大量的 CPU 资源,甚至导致整个进程挂起。

import repattern = re.compile(r"(a+)+$")pattern.match("a" * 10**6 + "!")

上面这个正则表达式就是典型的例子,它会在匹配特定字符串时陷入“回溯”困境,导致程序长时间无响应。

如何解决?

使用**re2(Google 的安全正则表达式引擎)。re2采用有限状态自动机,可以保证在线性时间**内完成匹配,从而避免了 ReDoS 攻击。import re2 as repattern = re.compile(r"(a+)+$")print(pattern.match("aaaa!")) # 安全或者,使用rure等工具来对正则表达式进行审计,确保它们是安全的。

假设你正在使用内部私有仓库来管理公司自己的 Python 包,并运行pip install yourlib来安装一个名为yourlib的包。你可能想当然地认为pip会从你的 Artifactory 仓库中获取它。但是,如果有人在公共的 PyPI 上上传了一个同名的恶意包,pip可能会优先从公共 PyPI 拉取那个恶意的包,而不是你期望的内部版本。这就是所谓的“依赖混淆攻击”。

如何解决?

正确使用--index-url或--extra-index-url来指定包的来源。pip install yourlib --index-url=https://internal.repo/simple

这些高级的 Python 安全问题,往往隐藏在那些看似“无害”的代码片段中。它们之所以难以被发现,是因为它们并非简单的语法错误,而是与程序的执行流程、库的底层机制以及生态系统本身的设计缺陷紧密相关。

安全开发不仅仅是避免已知的大坑,更是要深入理解你所使用的工具和库的底层工作原理。 它要求开发者具备一种“安全思维”,在编写每一行代码时,都考虑到潜在的滥用场景。

希望这篇深度剖析的文章能帮助你重新审视自己的 Python 代码,及时发现并修复那些可能存在的“定时炸弹”,从而构建出真正健壮、可靠和安全的应用程序。

来源:高效码农

相关推荐