Pickle远程执行有风险吗

wen python案例 12

本文目录导读:

Pickle远程执行有风险吗

  1. 核心风险:Pickle 本质上是“代码执行”
  2. 典型的攻击方式
  3. 为什么这是“远程执行”的风险?
  4. 官方警告
  5. 如何安全地使用 Pickle?

是的,Pickle(Python 的序列化模块)在远程执行或加载不可信数据时,存在极高的安全风险,这个问题在 Python 社区中是共识性的警告。

永远不要加载不受信任的、来源不明的或未经验证的 Pickle 数据。

以下是详细的风险分析、原理和最佳实践:

核心风险:Pickle 本质上是“代码执行”

Pickle 的设计初衷是为了方便 Python 对象的序列化和反序列化(保存和恢复状态),在反序列化过程中,Pickle 允许(并且实际上需要)调用自定义的 __reduce__ 方法或执行特定的指令码(opcode),这使得攻击者可以构造一个恶意的 Pickle 数据,当 pickle.loads() 被调用时,它会在你的程序进程中执行任意 Python 代码

简单类比:

Pickle 文件不是一个“数据文件”,而是一个“指令序列”,加载它就像在 eval() 中执行一个字符串,或者像一个可以自动运行的木马程序。

典型的攻击方式

攻击者可以构造一个 Pickle 负载,实现以下任意一种或多种攻击:

  1. 远程命令执行

    # 攻击者构造的恶意 pickle 字节(伪代码)
    import pickle
    import os
    class Evil:
        def __reduce__(self):
            # 返回一个可调用的对象(os.system)和其参数
            # 这里模拟了“反弹 shell”或执行任意系统命令
            return (os.system, ('rm -rf /',))  # 极其危险!
    # 攻击者将这个恶意 pickle 数据发送给受害者
    malicious_data = pickle.dumps(Evil())
    # 如果受害者执行 pickle.loads(malicious_data) 则立即执行 rm -rf /
    # 注意:实际攻击中常用更隐蔽的命令,如反弹shell、下载木马等
  2. 信息窃取:通过执行代码,读取服务器上的敏感文件(如配置文件、密钥、数据库密码等)并通过网络发送出去。

  3. 权限提升/横向移动:一旦在目标服务器上获得代码执行权限,攻击者可以尝试进一步攻击。

为什么这是“远程执行”的风险?

  • 场景1:Web 应用 你开发了一个 Flask/Django 应用,用户上传一个文件,你为了“方便”用 Pickle 加载了它来获取“数据”,攻击者可以上传一个恶意 Pickle 文件,获得服务器的控制权。
  • 场景2:消息队列/Redis 你将序列化后的 Python 对象存入 Redis 或 RabbitMQ,如果系统存在漏洞(如未授权访问或反序列化端点暴露),攻击者可以将恶意 Pickle 数据注入,导致消费者端代码执行。
  • 场景3:模型文件交换 在机器学习领域,很多人用 Pickle 保存模型(.pkl),从不可信来源下载的 .pkl 文件可能包含恶意代码,著名的案例包括恶意 torch.save() 模型(PyTorch 基于 Pickle)和 sklearn 模型文件。
  • 场景4:网络传输 在 Socket 通信或 HTTP 请求中,如果一方用 pickle.loads() 接收来自另一方的数据,而另一方不可信,就是远程代码执行。

官方警告

  • Python 官方文档 明确写道:

    The pickle module is not secure. Only unpickle data you trust.pickle 模块不安全,仅反序列化你信任的数据。) It is possible to construct malicious pickle data which will execute arbitrary code during unpickling. Never unpickle data that could have come from an untrusted source, or that could have been tampered with. (可以构造恶意的 pickle 数据,这些数据在反序列化期间会执行任意代码,永远不要反序列化可能来自不可信来源或被篡改过的数据。)

如何安全地使用 Pickle?

  1. 绝对原则:只加载来自受信任源的数据。

    这些数据应该是你自己生成的、经过完整性校验(如数字签名、HMAC)的,并且只在你控制的内部网络中使用,且保证传输过程安全(如 HTTPS、TLS)。

  2. 实施完整性校验(如果必须用 Pickle)
    • pickle.dumps() 之后,计算数据的 HMAC(消息认证码)或数字签名。
    • pickle.loads() 之前,验证签名是否一致,这可以防止数据在传输中被篡改,但不能防止你的应用程序逻辑本身产生的恶意数据(如果你的服务器被入侵,签名密钥也会泄露)。
  3. 根本解决方案:使用安全的序列化格式
    • 对于数据交换:使用 JSONjson 模块)、MessagePackProtocol Buffers(protobuf)或 Avro,它们只处理基本数据类型,不会执行代码,是安全的首选。
    • 对于需要序列化复杂 Python 对象:使用 jsonpickle(它通过 JSON 来表示对象,不执行代码)或 cloudpickle(同样不安全,但可用于内部分发)。
  4. 限制 Pickle 的使用场景
    • 应用程序内部缓存(同一进程内):如果你的程序自己保存和加载,并且确保没有人能修改文件系统,可以。
    • 同一机器上的进程间通信(通过本地文件或本地 Socket):如果文件权限设置严格,相对安全。
    • 在完全受信任的集群内的数据传输(所有节点由你控制,通信通道加密)。
  5. 绝对不要用在:
    • 接收用户上传的文件或HTTP请求体。
    • 接收来自外部API、其他公司的数据。
    • 接收来自公共网络(如互联网)的任何数据。
    • 存储在公开可读的缓存系统(如未加固的 Redis、Memcached)中。
场景 推荐使用 原因
跨语言、公开API、用户输入 JSON ( json ) 安全、标准、易于调试、跨语言
高性能、跨语言、大数据 MessagePack / Protocol Buffers 安全、速度快、体积小
Python进程间/内部可靠传输 JSON (首选) 或 Pickle(加HMAC) JSON 安全,Pickle 加校验可接受
机器学习模型文件交换 ONNX / TorchScript / 安全序列化库 避免直接加载 .pkl,即使来自你信任的源,也推荐使用标准模型格式
需要序列化复杂Python对象 pickle(绝对信任源)dill/cloudpickle(同样不安全,仅限内部分发) 如果必须,确保来源绝对可靠,数据是使用 HMAC 签名的。

“Pickle 远程执行有风险吗?”——答案是:有,而且是特别高的风险,属于高危漏洞类型(代码执行)。

在实践中,几乎所有的安全审查都会将反序列化不可信数据的 Pickle 调用判定为严重漏洞。 除非你完全控制数据来源和传输管道,否则请使用 JSON 等安全格式,如果不得不使用 Pickle,务必做好签名验证,并确保签名密钥的安全。

抱歉,评论功能暂时关闭!