Уязвимости механизма авторизации
В очередной раз пересматривая наши наработки по обнаружению уязвимостей в механизме авторизации веб-приложений, понял, что не знаю о вменяемом тексте на русском языке, который дает декомпозицию явления и рассматривает его со всех сторон. В результате, появился данный текст. Очень прошу оставить feedback на тему того, понятно ли написано, есть ли спорные моменты и был ли полезен данный текст. Буду переписывать до тех пор, пока не станет доходчиво, как в букваре. Заранее спасибо.
Задача механизма авторизации — предоставить ответ на вопрос, разрешено ли пользователю совершить запрашиваемое им действие. В основе механизма авторизации лежат формальные модели разграничения доступа, самыми известными среди которых являются модель Белла-ЛаПадулы, дискреционная модель и модель RBAC (разграничение доступа на основе ролей).
В веб-приложениях стандартом де-факто является реализация разграничения доступа на основе ролей. В модели RBAC решение о доступе субъекта к объекту принимается на основе привилегий, которыми наделена его роль. Рассмотрим модельную схему работы механизма авторизации, основанного на модели RBAC:
Шаг 1. Установление субъекта U, целевого объекта O и запрашиваемого действия A.
Шаг 2. Определение роли R субъекта U.
Шаг 3. Проверка наличия у роли R привилегии, разрешающей доступ A от пользователя U к объекту O.
Замечание. Список привилегий пользователя может быть задан либо как белый, либо как черный список. При описании привилегий с помощью белого списка явно указывается список объектов и действий над ними, разрешенных субъекту. Если запрашиваемое действие не входит в белый список, оно запрещается. При реализации привилегий с помощью черного списка явно указывается список объектов и действий над ними, запрещенных субъекту. Если запрашиваемое действие не входит в черный список, оно разрешается. Возможен и комбинированный вариант – в таком случае используются правила и для запрещения и для разрешения доступа.
В зависимости от места и первопричины предлагается выделять следующие виды уязвимостей авторизации:
- Роль пользователя находится под его контролем. Так бывает, когда определение роли пользователя происходит на основе входных данных, которые полностью контролируются пользователям. Примером такой уязвимости является возможность выставления флага isAdmin = true, передаваемого в cookies. В соответствие с общеизвестной классификацией уязвимостей по этапам жизненного цикла ПО, данный вид уязвимостей относится к уязвимостям проектирования. Действительно, ответственность за появление уязвимостей подобного рода лежит на системном архитекторе.
- Неполный список привилегий пользователя. Данная ошибка обычно встречается при описании привилегий в виде черного списка. В этом случае отсутствие правила для запрещения доступа к объекту автоматически приводит к разрешению доступа. Примером такой уязвимости является конфигурационный файл веб-сервера, в котором указан неполный список директорий, для которых необходимо провести авторизацию. Данный вид уязвимостей относится к уязвимостям внедрения и эксплуатации. Действительно, ответственность за появление уязвимостей подобного рода лежит не на разработчиках, а на администраторах приложений.
- Отсутствие обращения к механизму авторизации на пути выполнения, ведущем к защищенной функциональности. Данный вид уязвимостей относится к уязвимостям реализации. Действительно, ответственность за появление уязвимостей подобного рода лежит полностью на программисте, который не добавил обращение к механизму авторизации.
Необходимо разделять понятия проявления уязвимости и причины уязвимости (их виды описаны выше). Под проявлением уязвимости понимается любое свидетельство о наличии уязвимости в поведении приложения. У одной и той же уязвимости может быть множество проявлений. Например, если роль пользователя находится под его контролем, то реализовать повышение привилегий злоумышленник может из любого интерфейса веб-приложения, в котором обрабатывается входной параметр, отвечающий за роль пользователя.
При анализе приложения методом черного ящика обнаружения уязвимостей сводится к обнаружению проявлений уязвимостей. Действительно, установить первопричину уязвимости при работе с приложением, как с черным ящиком, в общем случае не представляется возможным. Для каждого вида уязвимостей авторизации можно определить арность отношения «проявление уязвимости» — «причина уязвимости»:
- Как уже было показано, в случае контроля пользователем своей роли арность отношения – «многие к одному». Нескольких уязвимостей данного вида в одном и том же приложении быть не может по определению.
- В случае неполного списка привилегий, арность отношения так же – «многие к одному». Действительно, обнаружение возможности совершить любое из запрещенных действий свидетельствует о неполной конфигурации. Аналогично с предыдущим, в приложении такая уязвимость либо есть, либо отсутствует.
- В случае отсутствия обращения к механизму авторизации, арность отношения – «многие ко многим». Действительно, проявление такой уязвимости может случиться только при выполнение пути с отсутствующей проверкой. На других путях данная уязвимость проявляться не будет по определению. Более того, отсутствующие проверки на других путях будут выливаться в свои, особенные, проявления уязвимости, так как для выполнения этих путей потребуется передать другие входные данные. Уязвимостей такого вида в приложении может быть сколько угодно.
Переходя к рассмотрению задачи обнаружения уязвимостей механизма авторизации методом черного ящика, можно сделать следующие выводы:
- Уязвимости механизма авторизации первого и второго вида (контроль роли пользователем и неполный список привилегий) можно обнаружить, найдя хотя бы одно их проявление. Вопрос полноты в данном случае не стоит (уязвимость может быть только одна), однако актуален вопрос точности.
- При обнаружении уязвимостей механизма авторизации третьего вида (отсутствие обращения к механизму авторизации на пути выполнения) возникает вопрос полноты анализа. Действительно, так как проверка авторизации должна быть на всех путях выполнения, ведущих к защищенной функциональности, возникает нетривиальная задача вызвать выполнение всех этих путей. Данная задача, как известно1, в общем случае неразрешима.
Сноска 1. Если бы была решена задача нахождения входных данных, в результате запуска с которыми будет выполнен заданный путь, то автоматически была бы решена задача определения выполнимости путей. Доказано, что эта задача неразрешима.
В целом все просто и понятно. Классификация «от места и первопричины» предлагается вами?
Ага, нами. Нужна для того, чтобы легче было сравнивать возможности различных методов обнаружения уязвимостей авторизации.
Top of mind:
Грани в этой классификации достаточно размытые.
Например, вся разница между вторым и третьим типом в том, как происходит контроль доступа — либо централизованно при помощи какого-нибудь authorization middleware, либо in-place непосредственно перед выполнением действия. Так?
При этом разница в «арности» здесь довольно спорная. Представь себе, например, конфиги authorization middleware для какого-нибудь очень большого веб-приложения. Их размеры могут составлять сотни килобайт, так что одно обнаруженное проявление со словами «ну, у вас конфиги неправильные» — не совсем то, что нужно разработчикам приложения от аудита безопасности. Так что я бы сказал, что в большом масштабе эта разница уже никого не волнует.
«Арность» первого класса — также довольно спорный момент. Причисляя сюда помимо случая «роль в руках у идиота^W пользователя» также более общее «пользователь может влиять на свои привилегии»(а иначе куда девать этот случай?), получаем, что несколько таких уязвимостей запросто могут сосуществовать в рамках одного веб-приложения.
Отсюда приходится делать вывод, что, generally speaking, все для трех предложенных типов одинаково актуальны вопросы полноты.
Другое дело что __статистически__ на данный момент в системах среднего и малого размера твои замечания по поводу арности остаются более-менее актуальными.
Хотя, frankly speaking, я бы второй и третий тип объединил бы в один, так как в моей задаче blackbox-анализа разница роли не играет. А первый класс оставил бы в стороне, сказав, что, в общем случае, такие баги в блэк-боксе можно найти только фаззингом, так как по сути это вариант security by obscurity, стало быть — неинтересно.
Согласен, классификацию надо или переделывать или выкидывать. Можно придумать две цели для нее: insight в понятие уязвимости механизма авторизации (т.к. описываются причины) или сравнение методов обнаружения уязвимостей.
Я бы сфокусировался отдельно на первой цели и попробовал привести все в более строгий вид. Например, ввести иерархию в первый вид, ибо частный случай контроля привилегий на стороне клиента будет как раз контроль роли (тот самый случай с isadmin = true).
А разница между вторым и третьим видом действительно архитектурная. Т.е. читатель сможет понять, как может быть организован контроль доступа с точки зрения архитектуры защищаемого веб-приложения, и какие риски есть у каждого варианта.
Сделаю update текста и отправлю комментарием сюда.
Вторая цель, как ты понимаешь, завязана на первую. И в этом плане и для инсайта и для сравнения(правда, сравнения на уровне «кажется, здесь у этого метода факап, а у этого вроде ничего», а не на уровне сравнения по всей строгости с четкими критериями) такая типизация вполне годится.
Просто не стоит требовать от нее слишком уж многого.
Надо сказать, что классификация в отношении access control flaws хромает вообще у всех. Я помнится смотрел, что по этому поводу думает CWE, и построил такой вот граф: http://lvk.cs.msu.su/~ngo/cwe.png . В целом, никакой ясности он не вносит, хотя своя логика есть и тут.
Не совсем так. Для инсайта (под разными углами, конечно) можно построить массу различных классификаций. Не все из них сгодятся для сравнения.
Я бы сказал, что классификации уязвимостей хромают вообще у всех. Яркий пример — WASC. Именно поэтому я подстелил соломку и не назвал свои пункты классами, а назвал видами. Но понимание того, что это не классификация, не избавляет от фактических ошибок в описании арности, да.
В жизни встречаются вещи типа «слабый хэш пароля» в СУБД, отсутствие фильтра перебора, отсутствие привязки сессии к ИП, просто передача авторизационных данных в незащищенном виде, авторизация без одного из обязательных ключей, передача одного из сессионных ключей в URL (вот буквально на дня проводит такой вектор через картинку на удаленном хосте, который записывал REFERER), это все подходит под «механизмы авторизации»?
В работах встречается у кого как, а если все нормализовать — будет очень здорово.
Нет, это все проблемы аутентификации. Механизм аутентификации отвечает на вопрос, действительно ли запрос пришел от того человека, который представился в запросе. Все, что ты перечислил — это как раз fail механизма проверки аутентичности запроса.
Задача авторизации — ответить на вопрос, разрешено ли запрашиваемое действие данному пользователю. Т.е. в уязвимостях авторизации злоумышленник не выдает себя за другого, он все выполняет из-под своей учетной записи (или из-под public) — как следствие, аутентичность всех запросов полнейшая :)