Фон

Прежде чем мы перейдем к сути этого поста, нам нужно взглянуть на несколько концепций в appsec. Первый касается совместного использования ресурсов между источниками (CORS). Это сложный механизм безопасности, встроенный во все современные браузеры. Если вы не знакомы с тем, что это такое и как работает, вам следует прочитать эту очень хорошую статью об этом. Вторая концепция касается файлов cookie HttpOnly. Если вы не знакомы, вы можете прочитать об этом здесь.

Настройка

Для этого упражнения мы собираемся использовать приложение / API, которое я описал в предыдущем сообщении блога здесь в качестве примера. Чтобы нарисовать эту картину, мы предположим следующее:
1) У нас есть конечная точка, которая должным образом проверяет файлы cookie сеанса.
2) Файлы cookie сеанса должным образом защищены флагами httponly и secure
3) Токены CSRF не используются приложением
4) Полный набор заголовков сервера выглядит следующим образом:

Как вы можете видеть на изображении выше, для файла cookie сеанса установлено два флага; безопасный и HttpOnly. Флаг HttpOnly, установленный для нашего файла cookie сеанса, означает, что браузер не позволяет нам получать доступ к cookie с помощью JavaScript. Или можем?

Введите XMLHttpRequest

XMLHttpRequest - замечательная функция JavaScript, которая позволяет разработчикам взаимодействовать с сервером и позволяет динамически обновлять страницу без необходимости обновлять страницу. Это делает веб-приложения чистыми и яркими. Ниже приведен код вредоносного веб-сайта с частью JavaScript, использованный для выполнения атаки:

Однако, поскольку это JavaScript, нам не следует разрешать через клиентский скрипт доступ к cookie, согласно статье OWASP на эту тему. Обычно это так, но XMLHttpRequest имеет свойство с именем withCredentials. Согласно статье, свойство withCredentials «является логическим, которое указывает, следует ли выполнять межсайтовые запросы управления доступом с использованием учетных данных, таких как файлы cookie или заголовки авторизации». Итак, согласно всему, что у нас есть до сих пор, мы можем использовать файлы cookie сеанса программно, если не установлен флаг HttpOnly, верно?

Неправильный. Похоже, что существует исключение из запрета доступа к клиентскому сценарию для XMLHttpRequest, которое по-прежнему позволит вам получить доступ к cookie сеанса даже с установленным флагом HttpOnly, если для свойства withCredentials установлено значение true. Это означает, что мы по-прежнему можем выполнять CSRF, используя cookie сеанса жертвы, который должным образом защищен флагом HttpOnly.

CORS всегда есть улов

Если вы просмотрели статью о CORS, которую я связал в фоновом разделе, вы увидите, что у нас есть еще одно препятствие для выполнения этого CSRF. CORS - это сложная концепция безопасности, от которой страдают многие веб-разработчики. Это также отрава для многих злоумышленников. Когда я впервые попытался выполнить CSRF в веб-приложении, я продолжал видеть следующую ошибку в консоли, когда я тестировал свой POC. «Запрос на другой источник заблокирован: та же политика происхождения запрещает чтение удаленного ресурса…».

Поскольку на сервере-жертве нет заголовка Access-Control-Allow-Origin, похоже, что мы застряли. Ну вроде как. Как оказалось, мы по-прежнему отправляем наш запрос на сервер И запрос по-прежнему выполняется на сервере с использованием защищенного файла cookie сеанса! Ошибка означает, что запрос был заблокирован браузером. Однако при ближайшем рассмотрении мы видим, что браузер отклоняет только ответ. Что это значит?

Собираем все вместе

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

Допустим, у нас есть администратор, который входит в приложение, а затем получает фишинговое письмо со ссылкой на наш вредоносный сервер. Когда администратор переходит на вредоносный сервер, для сервера жертвы выполняется XMLHttpRequest, который обновляет adminId 1 с адресом электронной почты злоумышленника и паролем по их выбору.

Теперь из-за ограничений CORS мы получим ошибку, но она генерируется самим браузером. НЕ сервер. Это означает, что сервер получил запрос и добросовестно его выполнил, получив ожидаемый ответ. Однако мы не можем прочитать ответ. Итак, пока мы не рассчитываем на данные в ответе, как в этом конкретном сценарии, мы все равно можем выполнять CSRF. Даже при наличии защиты HttpOnly и CORS.

Исправление

Так получилось, что этот пробел был замечен и исправлен. Есть флаг cookie под названием SameSite. Это относительно новый флаг, и Mozilla считает его экспериментальным. Кроме того, PHP начиная с 7.3 включает эту возможность.

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

Код