Будьте в курсе последних событий, подпишитесь на обновления сайта

Атака типа CSRF

Атака типа CSRF

Здравствуйте! В этом уроке я хотел бы рассказать о такой  атаке как  CSRF.  Ведь нельзя говорить про AJAX и не упомянуть про очень важную деталь его реализации – защиту от CSRF-атак.

CSRF (Cross-Site Request Forgery, также XSRF) – опаснейшая атака, которая приводит к тому, что злоумышленник может выполнить на сайте массу различных действий от имени других, зарегистрированных посетителей.

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

Атака csrf

Злая форма

«Классический» сценарий атаки CSRF таков:

  • Петя является залогиненным на сайт, допустим, site.com. У него есть  сохраненная сессия в куках.
  • Петя попал на «злую страницу», например злоумышленник пригласил его сделать это письмом или каким-то другим способом.
  • На зараженной странице находится форма такого вида:
    <form action="http://server.com/send" method="POST"> <input type="hidden" name="message" value="Сообщение"> ... </form>
    
  • При заходе на зараженную страницу JavaScript вызывает form.submit, отправляя таким образом форму на server.com.
  • Сайт server.com проверяет куки, видит, что посетитель авторизован и обрабатывает форму. В данном примере форма отправляет посылку сообщения.

Итог атаки – Петя, зайдя на зараженную страницу, получается отправил письмо от своего имени. Содержимое письма сформировано злоумышленником.

Защита

В примере выше атака использовала, так называемое  слабое звено авторизации.

Куки позволяют сайту server.com проверить, что пришёл именно Петя, но ничего не говорят про данные, которые он отправляет.

Иначе говоря, куки еще  не гарантируют, что форму создал именно Петя. Они только удостоверяют личность, но никак не данные.

Типичный способ защиты сайтов – это  такой «секретный ключ» (secret), специальное значение, которое генерируется рандомным образом и хранится в сессии посетителя. Его знает только сервер, посетителю его знать необязательно.

Читайте также  Сравнение транспортов и их возможностей

Затем на основе ключа генерируется специальный «токен» (token). Токен делается так, чтобы с одной стороны он был отличен от ключа, в частности, может быть много токенов для одного ключа, с другой – чтобы было легко проверить по токену, сгенерирован ли он на основе данного ключа или нет.

Для каждого токена нужно дополнительное случайное значение, которое называют «соль» salt.

Вот формула вычисления токена:

token = salt + ":" + MD5(salt + ":" + secret)

Например:

  1. В сессии хранится secret=»abcdef», это значение создаётся 1 раз.
  2. Для нового токена сгенерируем salt, например пусть salt=»12345″.
  3. token = «12345» + «:» + MD5(«12345» + «:» + «abcdef») = «12345:5ad02792a3285252e524ccadeeda3401».

Это значение – с одной стороны, случайное, с другой – имея такой token, мы можем взять его первую часть 12345 в качестве salt и, зная secret, проверить по формуле, верно ли он вычислен.

Не зная secret, невозможно сгенерировать token, который сервер воспримет как верный.

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

То есть, «честная» форма для отсылки сообщений, созданная на http://server.com, будет выглядеть так:

<form action="http://server.com/send" method="POST"> 
<input type="hidden" name="csrf" value="12345:5ad02792a3285252e524ccadeeda3401"> 
<textarea name="message"> ... </textarea> 
</form>

При её отправке сервер проверит поле csrf, удостоверится в правильности токена, и лишь после этого отправит сообщение.

«Зараженная страница» при всём своем  желании не сможет сгенерировать подобную форму, так как не владеет  ключом secret, и токен будет соответственно неверным.

Такой токен также называют «подписью» формы, которая и  удостоверяет, что форма сгенерирована именно на сервере.

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

token = salt + ":" + MD5(salt + ":" + secret + ":" + fields.money)

При отправке формы сервер проверит подпись, подставив в неё известный ему secret и присланное значение fields.money. При несовпадении либо secret не тот (хакер), либо fields.money изменено.

Читайте также  XMLHttpRequest и возобновляемая закачка

Токен и AJAX

Теперь перейдём к AJAX-запросам.

Что если посылка сообщений в нашем интерфейсе реализуется через объект XMLHttpRequest?

Как и в случае с формой, мы должны «подписать» запрос токеном, чтобы гарантировать, что его содержимое прислано на сервер именно интерфейсом сайта, а не «зараженной страницей».

Здесь возможны варианты, самый простой – это дополнительная кука.

  1. При авторизации сервер  например устанавливает куку с именем CSRF-TOKEN, и пишет в неё токен.
  2. Код, осуществляющий XMLHttpRequest, получает куку и ставит заголовок X-CSRF-TOKEN с ней:
    var request = new XMLHttpRequest(); 
    var csrfCookie = document.cookie.match(/CSRF-TOKEN=([\w-]+)/); 
    if (csrfCookie) { request.setRequestHeader("X-CSRF-TOKEN", csrfCookie[1]); 
    }
  1. Сервер проверяет, есть ли заголовок и содержит ли он верный токен.

Защита действует потому, что прочитать куку может только JavaScript с того же домена. «Зараженная страница» не сможет «переложить» куку в заголовок.

Если нужно сделать не XMLHttpRequest, а, к примеру, динамически сгенерировать форму из JavaScript – она также подписывается аналогичным образом, скрытое поле или дополнительный параметр генерируется по куке.

Итоги

  • CSRF-атака – это когда «зараженная страница» отправляет форму или запрос на сайт, где посетитель, предположительно, авторизован. Если сайт проверяет только куки, то он такую форму принимает. А делать это не следует, так как её сгенерировал злоумышленник.
  • Для защиты от атаки формы, которые генерирует server.com, подписываются специальным токеном. Можно не все формы, а только те, которые осуществляют действия от имени посетителя, то есть и  могут служить объектом атаки.
  • Для подписи XMLHttpRequest токен дополнительно записывается в куки. Тогда JavaScript с домена server.com сможет прочитать её и добавить в заголовок, а сервер – проверить, что заголовок есть и содержит корректный токен.
  • Динамически сгенерированные формы подписываются аналогично: токен из куки добавляется как URL-параметр или дополнительное поле.
Поделиться

Об авторе

admin administrator

Сообщить об опечатке

Текст, который будет отправлен нашим редакторам: