У меня есть маринованный экземпляр объекта и приходится принимать эти маринованные экземпляры из ненадежных источников. Существует внутреннее состояние (просто массив целых чисел), который я могу использовать для воссоздания экземпляра без выполнения какого-либо кода маринованного объекта. Поэтому мой вопрос заключается в том, что можно извлечь только некоторые объекты данных из рассола без выполнения какого-либо кода из него.Безопасное извлечение частичных данных из маринованных объектов
ответ
Вы можете сделать это, но только если вы сами проанализируете данные, не полагаясь на рассол, что может привести к произвольному выполнению кода. Очень простой пример выполнения может быть
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, если вы используете его с другими версиями.
Я боялся, что написать мой собственный парсер-парсер будет единственным способом решить эту проблему. Я, очевидно, не собираюсь делать это так, как реалистично, я собираюсь ввести более уязвимые ошибки, чем удаляет. Я просто хочу, чтобы пользователи конвертировали в какой-то разумный формат сериализации, и все. – user2952698
Идея может быть читать маринованные объекты из файлов в виде строк, а затем использовать 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
с.
Почему бы вам не использовать что-то другое, кроме 'pickle', если вам нужно принять ненадежные данные? Например, массив целых чисел может быть представлен в JSON. – jonrsharpe
Моя проблема в том, что мне приходится иметь дело с большим количеством устаревших объектов, которые я должен принять (и которые, очевидно, уже сериализованы с использованием pickle). Следующее лучшее решение, если извлечение данных из соленья невозможно, - это требовать от людей запускать конвертер. Хотя это работает, это не процедура, которую я хочу наложить на своих пользователей. – user2952698
Обратите внимание на красную рамку в верхней части [документации] (https://docs.python.org/2/library/pickle.html) - 'pickle' не подходит для этого задания. – jonrsharpe