Может ли кто-то аргументированно объяснить, в чём опасность сериализации данных в двоичном виде, или сослаться на хорошее объяснение? Аргументы вроде "это опасно по своей природе" или "это не может быть безопасно обработано", приведённые в "Deserialization risks in use of BinaryFormatter and related types", меня не убедили.
-
Комментарии были перемещены в чат; пожалуйста, не продолжайте дискуссию здесь. Прежде чем разместить комментарий ниже этого, пожалуйста, ознакомьтесь с назначением комментариев. Комментарии, которые не запрашивают уточнения или не предлагают улучшения, скорее всего должны быть ответами, размещены на Stack Overflow на русском Meta или написаны в Чат Stack Overflow на русском. Комментарии, продолжающие дискуссию, могут быть удалены.Grundy– Grundy ♦2024-07-29 14:43:22 +00:00Commented 29 июл. 2024 в 14:43
3 ответа
Суть в том что при десериализации форматтер может создать любой тип в памяти, вообще совершенно любой. Например если подсунуть куда-то свою либу со своим типом, а затем скормить форматтеру свой сериализованный объект, то он просто запустит ваш код без ведома приложения, которое ждёт какие-то данные.
Форматтер не учитывает видимость членов класса и даже не запускает контструктор так, как это делается с помощью new. Он создаёт экземпляры по сути вот так:
var obj = FormatterServices.GetUninitializedObject(typeof(MyType));
То есть если в конструкторе есть какая-либо защита целостности состояния объекта при создании экземпляра, её легко обойти вот таким образом. Ну а дальше на что фантазии хватит.
Да, форматтер быстрый и надёжный в плане создания снапшота объекта и записи его на диск или для передачи по сети, но при этом следует очень внимательно отнестись к нюансам безопасности.
По сути никто не запрещает его использовать, пользуйтесь наздоровье, но его вынесли из основного кода .NET во внешний пакет и прикрыли ключами в файле проекта не просто так. Поэтому установить и разлочить его придётся руками, это и есть подтверждение тому, раз вы решились всё-таки его использовать - то понимаете, что делаете.
В некоторых инфраструктурах форматтер - лучшее средство для максимально быстрой и удобной передачи данных между нодами в кластере, например через AMQP. То есть в защищённой от внешнего воздействия среде его вполне можно использовать, и его используют. Как минимум потому что ни один сериализатор не даст такой же производительности при использовании сложных объектов, хотя местами тот же JsonSerializer в последних (8+) дотнетах за счёт кодогенерации начинает догонять.
Смотрите, в чём дело.
У BinaryFormatter-а есть две больших проблемы: он не выполняет конструкторы (которые могут валидировать данные), и он полиморфный. Последняя проблема особенно опасна, поскольку при помощи этого атакующий легко может заставить BinaryFormatter создать объект по своему выбору. Например, следующим образом.
Пускай у атакующего есть возможность самому скрафтить бинарные данные для десериализации. Допустим, атакующий хочет создать в вашем процессе объект типа X. Если у вас десериализуется объект другого типа Y, атакующий может подсунуть в сериализованные данные объект нужного ему типа X. Приведение типов провалится, но объект типа X тем не менее будет создан.
(Если атакующий не хочет, чтобы были проблемы с приведением типов, он может подыскать сериализуемый тип Y, у которого есть поле типа object, и разместить экземпляр класса X в этом поле.)
А в чём опасность того, что будет создан какой-то объект? Ведь атакующий, в конце-концов, не управляет этим объектом? Дело в том, что в .NET есть много классов, которые могут быть опасны, если просто так окажутся в вашем процессе. Исследованию того, какие именно классы опасны, посвящён, например, проект why so serial, который приводит примеры опасных классов (и умеет создавать их десериализованное представление).
Самый простой пример — старый класс TempObjectCollection, который в своём финализаторе удаляет набор файлов, имена которых хранятся в поле объекта. Как вы понимаете, поле объекта контролируется атакующим, и он может «напихать» туда любые имена файлов.
Кроме того, такие классы вполне могут быть найтись не в стандартной библиотеке .NET, а найтись в популярных nuget-пакетах, или просто быть непреднамеренно написанными авторами атакуемой программы.
Но может быть, можно спасти BinaryFormatter, ограничив его лишь «белым списком» классов для десериализации? К сожалению, и это не поможет, по двум причинам.
Первая причина — практически весь код, использующий BinaryFormatter, исходит из полиморфизма. И этот код просто перестанет работать.
Вторая причина — десериализация, при которой обходится валидация значений в конструкторе тоже очень опасна. Например, даже если вы десериализуете массивы и словари с числовыми/строковыми ключами, всё равно атакующий может испортить ваш объект: в том же Dictionary<K, V> есть много полей, которые могут привести, например, к переполнению памяти.
Написано по мотивам:
-
-
-
Не совсем в тему, но мне кажется, что подобные проблемы с безопасностью надуманы. В нормально защищенной системе подобным атакующим просто не откуда взяться. А если систему не наделили внешней защитой, то в ней скорее всего просто нет никаких критически важных данных, т.е. и ломать что-то там смысла нет.avp– avp2024-07-31 20:34:31 +00:00Commented 31 июл. 2024 в 20:34
-
1@avp: Плюс, допустим что данные неважные. Их десериализация в любом случае может привести к катастрофе.VladD– VladD2024-07-31 21:29:24 +00:00Commented 31 июл. 2024 в 21:29
-
1@avp: Почему надуманные? Если у вас бежит сервер, который принимает от произвольного клиента поток байт и десериализует его, то он подвержен этой проблеме. Вот например почтовый сервер, к нему же может присоединиться любой? Если бы разбор емейла мог привести к таким вот проблемам, все SMTP-серверы бы были огромной дырой в безопасности.VladD– VladD2024-07-31 21:36:54 +00:00Commented 31 июл. 2024 в 21:36
Коротко - BinaryFormatter не совместим между разными версиями .NET.
Ещё он устарел и не подреживается в последних версиях .net
Eсли вы сериализуете им данные в одной версии, а потом обновите версию .net в проекте, то будут ошибки десериализации. Либо если на клиенте и сервер отличается версия .net
-
1Вопрос таки был про безопасность, а не про совместимость )CrazyElf– CrazyElf2024-07-30 10:58:41 +00:00Commented 30 июл. 2024 в 10:58