Сериализация и десериализация питон

Безопасная разработка в Python. 2 часть

В первой части статьи мы начали разбирать тему безопасной разработки на языке Python, поговорили о том, что нельзя допускать бесконтрольное выполнение команд, вводимых пользователем, также нельзя позволять вводить ключи к некоторым командам. Также, вспомнили про SQL инъекции и рассмотрели общие рекомендации по защите. Однако, в той или иной степени все приведенные в первой статье уязвимости свойственны и другим языкам программирования. В этой статье мы рассмотрим более свойственные именно для языка Python уязвимости. И начнем мы с такой интересной темы как десериализация.

Метод Pickle

Итак, рассмотрим, что такое сериализация и десериализация в Python. Сериализация это способ преобразования структуры данных в линейную форму, которую можно сохранить в файле или передать по сети. Обратный процесс преобразования сериализованного объекта в исходную структуру данных называется десериализацией. Прежде, чем начать говорить о недостатках данного метода мы разберем примеры того, как работает сериализация.

Для сериализации данных в Python используется метод Pickle. Это собственный формат сериализации объекта в Python. Интерфейс метода pickle содержит четыре метода: dump, dumps, load, и loads. Метод dump() сериализует в открытый файл (файл-подобный объект). Метод dumps() сериализует в строку. Метод load() десериализует из открытого файлового объекта. Метод loads() десериализует из строки.

>>> import pickle >>> data = < . 'a': [1, 2.0, 3, 4+6j], . 'b': ("character string", b"byte string"), . 'c': . > >>> >>> with open('data.pickle', 'wb') as f: . pickle.dump(data, f) . >>> with open('data.pickle', 'rb') as f: . data_new = pickle.load(f) . >>> print(data_new)

Как видно в data_new мы получили набор данных data в сериализованном виде. Метод Pickle поддерживает по умолчанию текстовый протокол, но имеет также двоичный протокол, который более эффективен, но не удобен для чтения при отладке. Обычно при хранении данных используют как раз двоичный вариант Pickle.

Читайте также:  Zip для python 3

Десериализация без проверок

Серьезным недостатком метода Pickle является то, что при выполнении методов load и loads не происходит проверка содержимого файла, который необходимо десериализовать. То есть существует возможность составить файл pickle таким образом, что в результате его десериализации злоумышленник сможет выполнить произвольный код с правами пользователя, запустившего данный скрипт.

Ниже приводится пример скрипта для Python 2.0, который готовит специальный Pickle файл. Этот файл после десериализации запускает командную оболочку.

import cPickle import subprocess import base64 class Exploit(object): def __reduce__(self): fd = 20 return (subprocess.Popen, (('/bin/sh',), # args 0, # bufsize None, # executable fd, fd, fd # std )) print base64.b64encode(cPickle.dumps(Exploit()))

Как видно, в классе Exploit используется уже знакомая нам команда Popen, которая собственно и запускает шелл. Метод Pickle дампит результаты работы Exploit, и затем двоичный дамп кодируется Base64.

Таким образом, совершенно очевидно, что метод Pickle не является безопасным. У этого метода отсутствует контроль за целостностью данных и объектов, отсутствует контроль над размером данных или системных ограничений, код оценивается без мер безопасности, а строки кодируются и что еще важнее декодируются без проверки. И собственно, официальная документация по Pickle говорит нам следующее:

Warning: The pickle module is not intended to be secure against erroneous or maliciously constructed data. Never unpickle data received from an untrusted or unauthenticated source.

Рекомендации по безопасности

При десериализации из ненадежного источника, например если вы получаете сериализованный файл от пользователя никогда не используйте метод Pickle. Альтернативой может стать более безопасный метод JSON. Никогда не доверяйте данным, передаваемым пользователями. Никогда не производите десериализацию данных из ненадёжного источника с помощью pickle.

И немного про XML

Текстовый формат хранения данных XML получил широкое распространение. И практически в каждом языке есть специальные библиотеки для парсинга документов данного формата. Не является исключением и Python. При парсинге документов XML в Python обычно используют стандартную библиотеку XML. Однако, стандартная библиотека уязвима к некоторым DoS атакам. В частности, злоумышленник может отправить на разбор XML бомбу, которая может вызвать отказ в работе скрипта Python. Простейшая XML бомба имеет следующую структуру:

Здесь мы сначала формируем вхождение e содержащее длинную текстовую строку, а затем внутри тэга многократно повторяем данное вхождение.

На этом принципе построена атака Billion Laughs. В ней мы сначала формируем вхождения по принципу прогрессии, когда каждое следующее вхождение состоит из предыдущих (lol2 из lol, lol3 из lol2 и так далее). Таким образом, когда мы публикуем lol9, результирующий тег будет иметь очень большой размер, в результате чего возможен отказ в обслуживании.

И не только бомбы

Помимо XML при обработке XML в Python можно также столкнуться с другими видами атак. Например, возможны варианты, когда в XML документе будут выполнены обращения к посторонним веб ресурсам, как в примере ниже. Или, что еще хуже, возможен вывод на экран какого-либо текстового файла.

Безопасный XML

Для борьбы с такими атаками через XML файлы рекомендуется использовать специализированные библиотеки, например xml.etree.ElementTree или defusedxml.ElementTree .

Работать с этими библиотеками довольно просто:

>>> from xml.etree.ElementTree import parse >>> et = parse(xmlfile) >>> from defusedxml.ElementTree import parse >>> et = parse(xmlfile)

Заключение

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

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

  • что такое алгоритмы и зачем они нужны;
  • разбор основных алгоритмов сортировки: пузырьковая, сортировка выбором, сортировка вставками, быстрая сортировка;
  • разбор основных алгоритмов поиска: линейный поиск, бинарный поиск;
  • разбор примеров рекурсивных алгоритмов: вычисление факториала, чисел Фибоначчи;
  • примеры использования алгоритмов: сортировка списка, поиск элемента в массиве, нахождение наибольшего общего делителя.

Записаться на открытый урок можно по ссылке.

Источник

Сериализация и десериализация объектов Python: часть 1

Gigi Sayfan

Gigi Sayfan Last updated May 26, 2022

Сериализация и десериализация объектов Python является важным аспектом любой нетривиальной программы. Если в Python вы сохраняете что-то в файле, если вы читаете файл конфигурации или отвечаете на HTTP-запрос, вы выполняете сериализацию и десериализацию объектов.

В некотором смысле, сериализация и десериализация — самые скучные вещи в мире. Кто заботится обо всех форматах и протоколах? Вы просто хотите сохранить или стримить некоторые объекты Python и вернуть их позже.

Это очень здоровый способ взглянуть на мир на концептуальном уровне. Но на прагматическом уровне, какая схема сериализации, формат или протокол, которые вы выбираете, могут определять, насколько быстро работает ваша программа, насколько она безопасна, насколько свободно вы должны поддерживать свое состояние и насколько хорошо вы собираетесь взаимодействовать с другими системы.

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

Пример выполнения

В следующих разделах я буду сериализовать и десериализовать одни и те же графы объектов Python, используя различные сериализаторы. Чтобы избежать повторения, я определяю эти графы объектов здесь.

Простой Graph объект

Простой graph объект — это словарь, который содержит список целых чисел, строку, float, логическое и None.

simple = dict(int_list=[1, 2, 3], 

Источник

Оцените статью