2015-04-07 6 views
1

У меня есть маринованный экземпляр объекта и приходится принимать эти маринованные экземпляры из ненадежных источников. Существует внутреннее состояние (просто массив целых чисел), который я могу использовать для воссоздания экземпляра без выполнения какого-либо кода маринованного объекта. Поэтому мой вопрос заключается в том, что можно извлечь только некоторые объекты данных из рассола без выполнения какого-либо кода из него.Безопасное извлечение частичных данных из маринованных объектов

+2

Почему бы вам не использовать что-то другое, кроме 'pickle', если вам нужно принять ненадежные данные? Например, массив целых чисел может быть представлен в JSON. – jonrsharpe

+0

Моя проблема в том, что мне приходится иметь дело с большим количеством устаревших объектов, которые я должен принять (и которые, очевидно, уже сериализованы с использованием pickle). Следующее лучшее решение, если извлечение данных из соленья невозможно, - это требовать от людей запускать конвертер. Хотя это работает, это не процедура, которую я хочу наложить на своих пользователей. – user2952698

+0

Обратите внимание на красную рамку в верхней части [документации] (https://docs.python.org/2/library/pickle.html) - 'pickle' не подходит для этого задания. – jonrsharpe

ответ

0

Вы можете сделать это, но только если вы сами проанализируете данные, не полагаясь на рассол, что может привести к произвольному выполнению кода. Очень простой пример выполнения может быть

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, если вы используете его с другими версиями.

+1

Я боялся, что написать мой собственный парсер-парсер будет единственным способом решить эту проблему. Я, очевидно, не собираюсь делать это так, как реалистично, я собираюсь ввести более уязвимые ошибки, чем удаляет. Я просто хочу, чтобы пользователи конвертировали в какой-то разумный формат сериализации, и все. – user2952698

1

Идея может быть читать маринованные объекты из файлов в виде строк, а затем использовать pickletools.dis, чтобы увидеть, что в них ... только позволяет определенный список команд («STOP», „INT“, ...), чтобы быть в вторая колонка. Это отрицательно повлияет на рассол, имеющий какие-либо типы объектов, о которых вы беспокоитесь, и если вы ориентируетесь только на очень конкретный список базовых объектов python, вы можете это сделать безопасно. может.

Вот что вы получаете с pickletools.dis:

>>> 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 
>>> 

Это лучше, чем писать полный рассола анализатор, и, возможно, выполнимо, если вы хотите, чтобы простые объекты, такие как INT с.