Pau*_*lan 12 python serialization escaping pickle
每个人都知道pickle不是一种存储用户数据的安全方式.它甚至在盒子上都这么说.
我正在寻找在当前支持的版本中破坏pickle解析的字符串或数据结构的示例cPython >= 2.4
.有没有东西可以腌制而不是捣蛋?特定的unicode字符有问题吗?真的很大的数据结构?显然旧的ASCII协议有一些问题,但最新的二进制形式呢?
我对泡菜loads
操作失败的方式特别好奇,特别是当给出由泡菜本身产生的字符串时.是否有任何情况下pickle将继续解析.
?
有什么样的边缘案例?
编辑:这里有一些我正在寻找的东西的例子:
__setitem__
在设置实例变量之前,您无法可靠地pickle从dict继承并调用的对象__setstate__
.这可能是酸洗Cookie对象时的问题.见http://bugs.python.org/issue964868和http://bugs.python.org/issue826897STOP
标记实际上不会停止解析的情况 - 当标记作为文字的一部分存在时,或者更一般地,当没有在换行符之前存在时.这是一个非常简化的例子,说明了pickle对我的数据结构不喜欢什么.
import cPickle as pickle
class Member(object):
def __init__(self, key):
self.key = key
self.pool = None
def __hash__(self):
return self.key
class Pool(object):
def __init__(self):
self.members = set()
def add_member(self, member):
self.members.add(member)
member.pool = self
member = Member(1)
pool = Pool()
pool.add_member(member)
with open("test.pkl", "w") as f:
pickle.dump(member, f, pickle.HIGHEST_PROTOCOL)
with open("test.pkl", "r") as f:
x = pickle.load(f)
Run Code Online (Sandbox Code Playgroud)
众所周知,Pickle对于圆形结构来说有点滑稽,但如果你把自定义散列函数和set/dicts混合成混合物,那么事情会变得非常毛茸茸.
在这个特定的例子中,它部分地取消了成员的角色,然后遇到了游泳池.所以它然后部分地解开池并遇到成员集.因此它创建了集合并尝试将部分未打开的成员添加到集合中.此时它会在自定义散列函数中死亡,因为该成员仅部分取消了作用.我担心如果你在哈希函数中有一个"if hasattr ..."会发生什么.
$ python --version
Python 2.6.5
$ python test.py
Traceback (most recent call last):
File "test.py", line 25, in <module>
x = pickle.load(f)
File "test.py", line 8, in __hash__
return self.key
AttributeError: ("'Member' object has no attribute 'key'", <type 'set'>, ([<__main__.Member object at 0xb76cdaac>],))
Run Code Online (Sandbox Code Playgroud)
可以腌制类实例。如果我知道你的应用程序使用什么类,那么我就可以破坏它们。一个人为的例子:
import subprocess
class Command(object):
def __init__(self, command):
self._command = self._sanitize(command)
@staticmethod
def _sanitize(command):
return filter(lambda c: c in string.letters, command)
def run(self):
subprocess.call('/usr/lib/myprog/%s' % self._command, shell=True)
Run Code Online (Sandbox Code Playgroud)
现在,如果您的程序创建Command
实例并使用 pickle 保存它们,并且我可以颠覆或注入该存储,那么我可以通过self._command
直接设置来运行我选择的任何命令。
实际上,我的示例无论如何都不应该被视为安全代码。但请注意,如果该sanitize
函数是安全的,那么整个类也是安全的,除了可能使用来自不受信任的数据的 pickle 来破坏这一点。因此,存在一些安全的程序,但由于pickle 的不当使用而变得不安全。
危险在于,您使用 pickle 的代码可能会按照相同的原理被破坏,但在看似无辜的代码中,漏洞远不那么明显。最好的办法是始终避免使用 pickle 加载不受信任的数据。