Понимание уязвимостей CSRF

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

Веб-приложения могут отправлять запросы другому веб-приложению, не показывая никакого ответа. Поскольку эта атака возможна только в том случае, если пользователь вошел в систему и имеет действительный файл cookie сеанса, злоумышленник запрашивает веб-приложение от имени вошедшего в систему пользователя, сидя на другом веб-сайте. Эта уязвимость настолько критична, что Open Web Application Security Project (OWASP) включил ее в свой список 10 основных уязвимостей.

Как происходит атака?

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

Возьмем пример. Пользователь зашел на сайт электронной коммерции. Через некоторое время пользователь закрывает вкладку браузера и начинает просматривать какой-то другой веб-сайт. Тем временем он получает электронное письмо со ссылкой на вредоносный веб-сайт. В тот момент, когда он посещает веб-сайт, заказ делается от имени пользователя на веб-сайте электронной коммерции.

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

Реальный сценарий атаки

  1. Джек посещает xyz.com, входит в систему и покидает сайт, не выходя из системы.
  2. Джек посещает foo.com (вредоносный веб-сайт), который непреднамеренно выполняет запросы к xyz.com из браузера Джека.
  3. Браузер жертвы отправляет этот запрос вместе со всеми файлами cookie жертвы. Запрос кажется законным для xyz.com.

Предположим, что указанный ниже URL-адрес необходим для успешного выполнения GET-запроса к xyz.com для покупки книги. Приведенная ниже ссылка будет работать только в том случае, если пользователь успешно прошел аутентификацию на xyz.com.

https://xyz.com/buy.php?bookid=123&transfer_amount=99999

Поскольку Джек все еще авторизован на xyz.com, запрос отправляется и с его счета снимаются деньги на покупку книги.

Все запросы к веб-приложению, которые не реализуют механизм защиты от CSRF, автоматически становятся уязвимыми. Теперь предположим, что это запрос POST, а не запрос GET.

Код:

POST /buy.php HTTP/1.1 Host: xyz.com User-Agent: Any Webbrowser Cookie: phpsessid=SSDFE23UN5VYS8P0JE2V6SG&lastvisit=1398310259&user=Jack Content-Type: application/x-www-form-urlencoded; charset=UTF-8 Content-Length: 47 bookid=123&transfer_amount=99999

Теперь некоторые разработчики могут подумать, что выполнение запроса POST вместо запроса GET сделает веб-приложение более безопасным. Но это не тот случай, когда в веб-приложении есть уязвимость CSRF.

Когда веб-приложение хранит информацию о сеансе в файлах cookie, эти файлы cookie отправляются при каждом запросе к веб-приложению (применяются политики одного и того же происхождения), хранение маркеров сеанса в файлах cookie делает CSRF уязвимым.

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

Недостаток сохранения значения идентификатора пользователя и установки его в файле cookie

Предположим, для флага HTTP установлено значение «Ложь», и JavaScript смог прочитать данные о файлах cookie. Злоумышленник может использовать информацию о сеансе либо для повышения привилегий в веб-приложении, либо для прослушивания трафика, чтобы прочитать значение файла cookie. В этом случае оба пользователя будут иметь одинаковое значение сеанса, действительное для веб-сервера. Это когда атака CSRF происходит, когда веб-сервер не может аутентифицироваться между законным пользователем и злоумышленником.

Как предотвратить уязвимость CSRF?

Шаблон двойной отправки файла cookie: подлинный пользователь создает сеанс и устанавливает идентификатор сеанса в качестве файла cookie. Наряду с этим сервер генерирует еще один файл cookie — сгенерированную случайную уникальную строку или Nonce (число, используемое после удаления) — который устанавливается в качестве токена защиты от CSRF на компьютере пользователя. Значение токена непредсказуемо, поскольку оно меняется при каждом запросе. Для флага HTTP установлено значение «false», чтобы JavaScript мог прочитать и установить значение токена защиты от CSRF в поле скрытой формы.

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

В реальном сценарии форма «Обновить пользователя» содержит скрытый ввод, для которого требуется токен. Этот токен может быть реализован как хэш MD5 случайно сгенерированной строки. Токен сохраняется в переменных сеанса.

UpdateUser.aspx проверит, соответствует ли файл cookie с информацией о сеансе маркеру, полученному через запрос POST. Запрос выполняется, если они совпадают, в противном случае отклоняется.

Запрос, отправленный на веб-сервер авторизованным пользователем, для обновления данных его профиля

  • Авторизованный пользователь заполняет форму и отправляет запрос.
  • Cookie содержит информацию о сеансе пользователя и отправляет ее в заголовке запроса.
  • Значение токена (анти-CSRF) отправляется как часть тела запроса.
  • Веб-сервер сравнит токен защиты от CSRF с файлом cookie, присутствующим в заголовке. Данные профиля пользователя обновляются, если сравнение прошло успешно, в противном случае оно отклоняется.

Используя этот шаблон, вредоносный веб-сайт не сможет угадать значение токена защиты от CSRF. Злоумышленник может отправить запрос от имени пользователя, но он не сможет получить ответ, поскольку такие запросы будут отклонены веб-сервером из-за отсутствия токена защиты от CSRF или токена, соответствие с настройками cookie в шапке.

Сгенерированный токен никогда не сохраняется на стороне сервера; он меняется с каждым запросом. Чтобы предотвратить CSRF, необходимо реализовать одноразовый токен для каждого запроса. Можно также внедрить капчи на веб-сайте перед совершением платежа или обновлением данных пользователя, чтобы убедиться, что запрос сделан реальным пользователем, а не автоматическим запросом.

Реализация токенов Anti-CSRF в Model-View-Controller (MVC)

После реализации токена защиты от подделки в веб-приложении злоумышленник не сможет прочитать токен защиты от CSRF из-за политик того же происхождения. Источник также должен быть проверен веб-приложением, чтобы понять, исходит ли запрос из того же домена или нет.

Ниже представлена ​​реализация токена защиты от подделки в ASP.net:

Ввиду того, что мы будем использовать токены защиты от подделки для обновления сведений о профиле пользователя.

<html> <head> <title>Update User Profile</title> </head> <body> <div> Update Email <form action="Account/UpdateUser" method=post> Email <input type="text" name="email" value="" /><br /> @Html.AntiForgeryToken() <input type=submit value="Update" /> </form> </div> </body> </html>

Поле HTML, Anti-Forgery Token выглядит следующим образом:

<input name="__RequestVerificationToken" type="hidden" value="EW4QS1DQk7LRlXhB- r4ddwfsffmsRfbIKF2aTWGklW-SuiQYFKVJhZ564lOZP_KD6_Gh3kkF4MbT4YbfIsjqicKj239d8WH5Tj7IknOLXt-G- iU3fR5OFCn9_Itbhw1">

Теперь мы украсим метод действия «Обновить» атрибутом ValidateAntiForgeryToken в контроллере учетной записи в методе UpdateUser, который использует запрос POST.

[HttpPost] [ValidateAntiForgeryToken] public ActionResult Update (string username) { //Update user email return Content (Request.Form["email"] + " has been updated); }

При отправке формы атрибут ValidateAntiForgeryToken проверяет как элементы формы, так и файлы cookie на наличие RequestVerficationToken. Это гарантирует, что оба они имеют одинаковое значение. При успешной проверке действие может быть продолжено, в противном случае атрибут ValidateAntiForgeryToken выдает исключение:

Server Error in '/' Application. ________________________________________ The required anti-forgery cookie "__RequestVerificationToken" is not present.

Таким образом, рекомендуется использовать токен анти-CSRF в каждом запросе POST.

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

Чтобы снизить риск и сохранить доверие пользователей, веб-сайты должны принять корректирующие меры, чтобы устранить любые шансы на уязвимость CSRF в коде веб-приложения. В отсутствие токенов защиты от CSRF веб-приложение должно иметь возможность отклонить любой запрос, даже если запрос кажется законным. В следующих блогах мы увидим больше критических уязвимостей и способы их правильного устранения.