Безопасность на реальных примерах всегда более интересна.
Как тестировщик на проникновение, люблю, когда приходят проекты, построенные на фреймворках быстрой разработки (Rapid development), подобно Ruby-on-Rails, Django, AdonisJs, Express и так далее. Они позволяют очень быстро строить систему за счет того, что бизнес модели прокидываются сразу на все уровни, включая клиентский браузер. Model (модели бизнес объектов в базе) и ViewModel (контракт взаимодействия с клиентами) такие фреймворки часто объединяют вместе, чтобы избежать лишнего перекладывания из Model во ViewModel и обратно, REST сервисы автоматом генерируются. C точки зрения разработки можно просто разработать бизнес модель на сервере, и потом использовать ее сразу на клиенте, что несомненно увеличивает скорость разработки.
Еще раз, я не утверждаю, что вышеупомянутые фреймворки плохие, или с ними что-то не то, у них есть средства и инструменты правильной защиты, просто с ними разработчики делают больше всего ошибок. Такое встречал и на одном ASP.NET MVC проекте, в котором разработчики наделали те же уязвимости, выставляя Models вместо ViewModels…
Уязвимость: из-за слабой валидации полей входящих моделей от клиента, можно инжектить поля, которые не предусмотрены функциональностью, но есть в бизнес-модели. Например, есть метод, который позволяет менять только имя пользователя, а возвращает объект профиля пользователя. Что если скопировать возвращаемый объект, поменять в нем все свойства и послать заново на вход? Возможно получиться, что можно менять любое свойство объекта (пароль, роль), обходя стандартные workflow.
Из разных проектов, которые мы тестировали на безопасность, приведу реальные примеры. Все эти проблемные места были устранены, а любая лишняя информация на скриншотах скрыта.
Система 1
В этой системе в профиле можно было поменять только имя пользователя. Но подставив ещё Email, удалось поменять и логин пользователя. Более того, с этого мыла теперь уходили инвайты другим пользователям.
Система 2
В этот примере простому пользователю удалось поменять роль на админа, добавив поле roles, и по урлу /admin просто открыть админку системы со всеми транзакциями, пользователями, отчетами и так далее.
Система 3
В этой системе удалось продлить себе бесплатную подписку на неопределенный срок. Понятно, что стандартный подход требовал, чтобы была оплата.
Метод на вход принимал, казалось бы, только выбранный цвет по брендингу воркспейса, а возвращал объект всего воркспейса, включая полный дамп StripeCustomer объекта, который отражал оплату. Удалось вставить не просто поле, а громадный подобъект StripeCustomer, и в итоге один раз заплатив, или у другого пользователя захватить этот объект, и продублировать его на все свои воркспейсы.
Система 4
Ну и напоследок. В этой системе была та же проблема: можно было поменять пароль и ключ доступа в обход придуманному воркфлоу. Отсутствие защиты против CSRF и запоминание аутентификационных куков на долгий период, поднимало риск данной уязвимости до небес. Злонамеренный пользователь мог бы разместить на популярном ресурсе скрипт с запросом на изменение пароля текущего пользователя данной системы, и все пользователи, которые открыли бы этот ресурс, лишились бы доступа в систему.
В серверном коде в метаданных для этого поля стояло hide, это позволило не возвращать это поле клиенту в ответе, но во входных данных это поле обрабатывалось без проблем.
Посыл:
- Никогда не доверяйте входящим данным от пользователей, они могут делать с ними все, что угодно
- Осторожнее с системами, в которых нет отдельного слоя ViewModel-s, а работа идет непосредственно с моделями базы
- Исследуйте более детально средства защиты, которые предлагает вам ваш фреймворк
Вышеизложенная информация предоставляется только для учебных и просветительских целей, как делать свои системы не надо.
Денис Колошко, Penetration Tester, CISSP
Автор: dhound