网络安全Python篇:常见漏洞与防御全面解析
前言
随着 Python 在 Web 开发、人工智能及网络安全领域的广泛应用,其代码安全性越来越受到开发者的重视。由于 Python 的动态特性和丰富的标准库,在带来开发便利的同时,也引入了许多潜在的安全风险。本文将全面盘点 Python 开发中常见的安全漏洞及防御手段,内容涵盖格式化字符串、反序列化、沙箱逃逸、框架漏洞、代码混淆以及高危 Sink 函数总结。
1. 格式化字符串漏洞
在 Python 中,主要有两种格式化字符串的方式:
-
Python 2 时代的
%操作符格式化:"this is a %s" % "test" -
现代的
format()方法格式化:"this is a {}".format('test')或"this is a {test}".format(test='test')
安全隐患:
当格式化字符串的模板(template)由用户输入控制时,就会引发严重的安全问题。攻击者可以通过对象属性的向上层级引用,读取敏感配置甚至执行任意代码。
漏洞示例:
# 当用户可以控制 format 的字符串时
template = 'class of {0} is {0.__class__}'
print(template.format(42))
# 输出: class of 42 is <class 'int'>
从这个简单的例子可以看出,攻击者可以使用 __init__、__globals__ 等魔术属性读取上下文环境变量,甚至结合内置模块实现命令执行。
2. 反序列化漏洞
Python 的序列化机制(如 pickle)在处理不受信任的数据时极具危险性。pickle 在反序列化时会解析并执行特定的字节码,特别是当类中定义了 __reduce__ 魔术方法时。
2.1 Pickle RCE 演示
攻击者可以通过自定义 __reduce__ 函数返回一个可执行的系统命令(如 subprocess.Popen),在目标服务器反序列化该数据时触发执行。
import pickle
import pickletools
import subprocess
class A(object):
a = 1
b = 2
def __reduce__(self):
# 反序列化时执行系统命令弹计算器或反弹shell
return (subprocess.Popen, (('cmd.exe', '/c', 'calc'),))
# 生成恶意 payload
data = pickle.dumps(A())
# 打印 opcode 指令序列
pickletools.dis(data)
# 目标服务器执行 pickle.loads(data) 时即被入侵
2.2 防御方案:重载 find_class
为了抵御此类攻击,可以通过重载 pickle.Unpickler 的 find_class 方法来实施严格的白名单限制:
import builtins
import io
import pickle
# 定义允许反序列化的安全内置类型
safe_builtins = {
'range', 'complex', 'set', 'frozenset', 'slice'
}
class RestrictedUnpickler(pickle.Unpickler):
def find_class(self, module, name):
# 仅允许 builtins 模块中 safe_builtins 指定的类
if module == "builtins" and name in safe_builtins:
return getattr(builtins, name)
# 拦截其余一切反序列化请求
raise pickle.UnpicklingError("global '%s.%s' is forbidden" % (module, name))
def restricted_loads(s):
"""安全的反序列化辅助函数"""
return RestrictedUnpickler(io.BytesIO(s)).load()
2.3 其他存在风险的序列化库
除了 pickle,以下库处理不可信数据时也存在代码执行或拒绝服务风险:
-
PyYAML(使用yaml.load时,应替换为yaml.safe_load) -
marshal -
shelve
3. 沙箱逃逸 (Sandbox Escape)
在某些 CTF 题或在线代码评测系统(OJ)中,常常会提供一个受限的 Python 运行环境(沙箱)。攻击者的目标是突破限制,获取系统最高权限。
3.1 常用高危函数
-
代码执行:
eval/exec/compile -
反射与查看:
dir/type/getattr/setattr -
作用域字典:
globals/locals/vars
3.2 常见模块导入绕过
-
import os/from os import * -
__import__("os")/importlib.import_module('os') -
imp(Python2/3旧版本) /reload(os)
3.3 沙箱绕过思路 (Bypass)
-
查看内置模块: 使用
dir(__builtins__)查看当前沙箱还存留哪些内置对象。 -
继承链与基类搜索(最核心的 payload): 通过寻找已加载模块的子类,定位到危险模块(如
os中的system或popen):().__class__.__bases__[0].__subclasses__()或者利用全局作用域获取:
__init__.__func__.__globals__ -
利用 Pickle: 若沙箱未禁用
pickle模块,可直接用其反序列化执行任意代码。 -
利用底层的 C 库: 如果 Python 层面的模块全被删除,可以使用
ctypes或cffi调用 libc 中的函数。 -
字符串拼接绕过限制:
"__im" + "port__"
3.4 沙箱防御建议 (官方)
-
使用 Jython 并利用 Java 平台的 SecurityManager 来锁定程序权限。
-
使用
fakeroot或chroot避免真实环境受损。 -
结合底层系统技术(如 Docker、Cgroups、Namespace)部署严格的 Rootjail。
4. Web 框架安全
4.1 Django
历史典型漏洞:
-
CVE-2016-7401: CSRF Bypass 漏洞。
-
CVE-2017-7233/7234: 开放重定向漏洞 (Open redirect vulnerability)。
-
CVE-2017-12794: Debug 页面导致的信息泄露和 XSS 漏洞(生产环境切记关闭
DEBUG = False)。
配置错误导致的源码泄露:
当使用 Nginx 为 Django 做反向代理处理静态文件时,如果 location 配置缺少尾部斜杠,会导致目录穿越。
例如配置了 /static 映射到 /var/www/static,访问 /static../ 会由于 Nginx 的路径拼接缺陷,被代理读取到项目源码。
4.2 Flask
Flask 默认使用 客户端 Session (Client-side Session)。
它会将 session 数据使用 SECRET_KEY 签名后存储在用户的 Cookie 中。如果服务端的 SECRET_KEY 泄露(例如被硬编码在源码中传到了 Github),攻击者就可以使用该密钥随意伪造任意用户的 Session(比如修改 {"user_id": 1, "is_admin": true}),从而完全接管网站后台。
5. 代码混淆与保护
在安全对抗中,防守方常需对 Python 源码进行保护,防止逆向分析或源码泄露;攻击方也会对木马代码进行混淆以绕过杀软检测。常见方式包括:
-
基于 AST (抽象语法树) 变换: 改变代码结构但保持逻辑一致(如重命名变量、插入死代码)。
-
编译为
.pyc文件: 虽然可以被uncompyle6还原,但能防御最基础的查看。 -
Pyinstaller 打包: 将解释器和依赖打包成二进制 ELF/EXE 文件。
-
PyArmor 工具: 对函数和模块级进行加密,运行时动态解密,保护强度较高。
-
自定义 AES 加密引擎: 更改 Python 解释器源码(如 CPython),读取被加密为
.pye格式的文件。
6. Sink (常见危险函数触发点总结)
在进行 Python 代码安全审计时,重点审查以下 Sink 函数(数据最终流入并触发漏洞的地方):
6.1 命令执行
-
os.system/os.popen/os.spawn*/os.exec*/os.fork -
subprocess.Popen/subprocess.run -
asyncio.subprocess/asyncio.get_event_loop().subprocess_exec -
commands.getstatusoutput(Python 2) -
pty.spawn/pty.os -
platform.popen -
eval/exec/execfile(Python 2) -
input(在 Python 2 中相当于 eval(raw_input)) -
ctypes.CDLL(调用动态链接库中的系统命令)
6.2 文件读取 / 目录遍历
-
open/os.open -
urllib.request.urlopen('file://...') -
codecs.open -
fileinput.input -
types.FileType(仅 Python 2)
6.3 危险第三方库及组件
-
Template(Jinja2/Mako 等模板注入 SSTI) -
subprocess32
6.4 反序列化 / 数据解析
-
pickle/cPickle(Python 2) -
PyYAML(yaml.load) -
marshal -
shelve -
PIL(Image Math 等组件历史漏洞)
结语:
Python 的安全开发在于“防患于未然”。坚决不信任任何外部输入、在生产环境关闭一切 Debug 模式、谨慎使用反序列化和执行函数,是保障 Python 代码安全的铁律。希望本文能为大家在日常开发和安全审计时提供一份有力的参考。
需要学习更多或者获取更多资料查看:【有道云笔记】资料领取
更多推荐



所有评论(0)