Повторяться смысла нет, но вот ещё раз вспомнить, что делать разработчикам, чтобы не допустить подобную уязвимость у себя в проекте — лишним точно не будет.
✖️ Что НЕ сделали разработчики React'а?
Команда React не предусмотрела надёжную проверку и фильтрацию данных при десериализации входных нагрузок RSC (React Server Components). В результате они могли расширять свойства объектов без достаточной валидации (например, путём инъекции proto), что позволяло загрязнять прототипы (prototype pollution) и выполнять произвольный код на сервере.
✅ Что делать разработчикам?
Зависит от языка, поскольку на похожие грабли можно наступить и в некоторых других языках.
💻💻:
• Используйте структуры данных без прототипа: вместо пустых объектов
{} применяйте Object.create(null) или литерал {__proto__: null}. Это предотвратит наследование опасных свойств от Object.prototype.• При необходимости используйте ассоциативные коллекции — применяйте
new Map() и new Set() вместо обычных объектов. У них нет «прототипа» в классическом понимании, и методы вроде .get()/.has() возвращают только значения.• Замораживайте глобальные прототипы: например, вызов
Object.freeze(Object.prototype) (и/или Object.seal) заблокирует добавление или изменение свойств базового прототипа. Это затруднит атаки, но нужно учитывать, что многие библиотеки рассчитывают на динамическое расширение объектов.• При запуске Node.js можете указать флаг
--disable-proto=delete — он полностью удалит свойство __proto__ из стандартных объектов.• Санитизируйте имена полей при объединении/парсинге JSON: запрещайте или фильтруйте ключи вроде
__proto__, prototype, constructor и подобных. Лучше всего – явно разрешать (whitelist) только ожидаемые имена полей и отбрасывать все остальное.• Избегайте небезопасных merge-функций (например,
lodash.merge, рекурсивных функций объединения объектов) при работе с внешними данными. Если мёрдж неизбежен, тщательно проверяйте, как реализована функция: нет ли в ней присвоения прототипов или вызова setattr (в JS – методов вроде Object.assign/reduce).💻 Python:
• Не используйте
pickle, или хотя бы не выполняйте pickle.loads на входных данных. Если нужна сериализация, используйте безопасный формат (JSON, json/yaml без пользовательских конструкторов).• Избегайте рекурсивного слияния атрибутов объектов из пользовательских словарей. Любая функция типа
merge(src, dst) может при наличии поля __class__ или __globals__ обойти границы объекта и изменить класс или глобальные переменные. Проверяйте, что входные данные не содержат ключей, начинающихся с __ или равных именам методов объектов.• Ограничивайте динамическое добавление атрибутов. При необходимости используйте
__slots__ в классах или явно задавайте список полей (например, через dataclasses), чтобы неизвестные атрибуты просто игнорировались. По возможности не добавляйте атрибуты в классы по именам из JSON.• Проверяйте использование
setattr и init: ни в коем случае не допускайте передачи строкового кода или списка методов для выполнения через eval/instance_eval внутри __init__ или других «магических» методов.• Замораживайте и не раскрывайте конфиденциальные переменные: не давайте внешнему коду доступ к глобальному состоянию приложения (модули, конфиг и т.д.), тем более через
__globals__/__class__.Продолжение — в следующем посте.
#уязвимости