从pickle对象安全地提取部分数据

时间:2015-04-07 15:16:22

标签: python pickle

我有一个腌制的对象实例,必须接受来自不受信任来源的这些腌制实例。有一个内部状态(只是一个整数数组),我可以用来重新创建实例而不执行任何pickle对象的代码。因此,我的问题是,是否可以从pickle中仅提取一些数据对象而不从中执行任何代码。

2 个答案:

答案 0 :(得分:1)

一个想法可能是将文件中的pickled对象作为字符串读取,然后使用pickletools.dis查看其中的内容...只允许特定的命令列表('STOP','{{ 1}}',...)在第二列。如果您只关注基本python对象的非常具体的列表,那么 可能会 能够安全地做到这一点。

以下是您使用INT获得的信息:

pickletools.dis

这比编写一个完整的pickle解析器更好,如果你只想允许像>>> import pickletools >>> import pickle >>> >>> p1 = pickle.dumps(1) >>> p2 = pickle.dumps(min) >>> >>> pickletools.dis(p1) 0: I INT 1 3: . STOP highest protocol among opcodes = 0 >>> pickletools.dis(p2) 0: c GLOBAL '__builtin__ min' 17: p PUT 0 20: . STOP highest protocol among opcodes = 0 >>> 这样的简单对象,那可能是可行的。

答案 1 :(得分:0)

你可以这样做,但只有你自己解析数据,而不是依赖可能导致任意代码执行的pickle。一个非常简单的例子可能是

import pickle
import re

class Test(object):
    def __init__(self, l):
        self.internal_list = l
        self.foo = 2
        self.bar = 24

# Create a pickled version of an object
t = Test([1,2,3,4,5,6,7,8,9,10])
pickle.dump(t, open("test.pickle",'w'))

def find_last_integer(s):
    """ Parses a string to return the integer that it ends with
        e.g. find_last_integer("foobar312") == 312
    """
    return int(re.search(r"\d+$", s).group())

# Load the pickled data
data = open("test.pickle").read()
listdata = data[data.find("(lp"):].split('\n') # Assumes that the class will only contain one list
                                               # if you need more then look for all lines starting "(lp"

nelements = find_last_integer(listdata[0])

# Each element of the list should be of the form "In" or "aIn"
reconstructed = [find_last_integer(elem) for elem in listdata[1:nelements+1]]
print reconstructed

请注意,如果您将其与其他版本一起使用,我只在python 2.7.8 YMMV中测试了上述代码。