CSRF-уязвимости все еще актуальны

CSFR (Сross Site Request Forgery) в переводе на русский — это подделка межсайтовых запросов. Михаил Егоров (0ang3el) в своем докладе на Highload++ 2017 рассказал о CSRF-уязвимостях, о том, какие обычно используются механизмы защиты, а также как их все равно можно обойти. А в конце вывел ряд советов о том, как правильно защищаться от CSFR-атак. Под катом расшифровка этого выступления.


О спикере: Михаил Егоров работает в компании Ingram Micro Cloud и занимается Application security. В свободное время Михаил занимается поиском уязвимостей и Bug hunting и выступает на security-конференциях

Дисклаймер: приведенная информация является сугубо мнением автора, все совпадения случайны.
rxzuuu_ccpo8uw9opgjbutrs-hk.jpeg

В том, что CSRF-атаки работают виноват этот Cookie-монстр. Дело в том, что многие веб-приложения используют куки (здесь и далее считаем уместным называть cookies по-русски) для управления сессией пользователя. Браузер устроен так, что, если у него есть куки пользователя для данного домена и пути, он их автоматически отправляет вместе с HTTP-запросом.

Cookies


Куки — это небольшой фрагмент данных, который веб-сервер отправляет клиенту в виде name=value в HTTP-заголовке c названием «Set-Cookie». Браузер хранит эти данные на компьютере пользователя, и всякий раз при необходимости пересылает этот фрагмент данных веб-серверу в составе HTTP-запроса в HTTP-заголовке с названием «Cookie».

Куки могут иметь различные атрибуты, такие как: expires, domain, secure, httponly:

Впервые куки появились в браузере Netscape в далеком 1994 году. До сих пор многие веб-приложения используют их для управления сессией пользователя.
jahhuedxwbccdc82v97tqub7geq.jpeg

Рассмотрим, как работает классическая Сross Site Request Forgery (CSRF) атака.

Допустим, в нашем веб-приложении есть возможность изменять адрес доставки у пользователя, и оно использует куки для управления сессией.

У нас есть HTML-форма, которую пользователь должен заполнить: ввести адрес и нажать кнопку «Сохранить». В результате в бэкенд полетит POST-запрос с HTML-формой. Мы видим, что браузер автоматически поставил туда сессионные куки пользователя. Бэкенд, когда получит такой запрос, посмотрит, что есть такая сессия, это легитимный пользователь, и изменит ему адрес доставки.

Что может сделать атакующий?
3ncnehuga46_ltfvzfsgm3pb1ii.jpeg

Он может на своем сайте attacker.com разместить такую HTML-страничку, которая на самом деле сабмитит HTML-форму на сайт example.com. Так как браузер автоматически вставляет куки пользователя в HTTP-запрос, то бэкенд просто не поймет, является ли данный запрос легитимным — результат ли это заполнения формы пользователем, или это CSFR-атака — и поменяет адрес доставки для пользователя на значение, которое выгодно для атакующего.

Есть другой вариант CSFR-атаки с использованием XHR API. Если о CSFR-атаке с использованием HTML-форм слышали многие, то о данном способе знают меньше, но он тоже работает.
vntws3ykrle2c_xr6ztikub5q60.jpeg

Обратите внимание на атрибут withCredentials, который заставляет браузер автоматически отправлять куки пользователя. Так как значение Content-type равно application/x-www-form-urlencoded, то браузер данный запрос отправит без CORS options preflight request, и опять CSFR-атака будет работать.

Рассмотрим более наглядно, как это происходит.
ryw2dquhy1hnddg0mkufscf8k4m.jpeg

Исходные данные:

  • приложение example.com, которое уязвимо к CSFR,
  • пользователь,
  • сайт атакующего, где есть страничка csrf-xhr.html.


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

История CSRF-атак


Вообще о CSRF-атаках известно с 2001 года, когда их начали активно эксплуатировать. В период 2008–2012 такие уязвимости были на каждом первом сайте, в том числе:

  1. YouTube;
  2. The New York Times;
  3. Badoo;
  4. Slideshare;
  5. Vimeo;
  6. Hulu;
  7. КиноПоиск;


Насколько серьезны CSRF-уязвимости?


На самом деле, все зависит от критичности уязвимого действия. Это может быть:

  • Account takeover — атакующий захватывает аккаунт жертвы путем смены email через CSRF.
  • Privilege Escalation — повышение привилегий за счет того, что атакующий через CSRF создает нового пользователя с высокими правами в системе.
  • Remote code execution — выполнение кода за счет эксплуатации command injection в админке через CSRF.


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

В проекте OWASP Top 10, который содержит 10 наиболее критичных уязвимостей в приложении, в 2010 году CSRF-уязвимости находились на 5 месте. Потом разработчики начали имплементировать различные варианты защиты и уже в 2013 году CSRF-уязвимости сместились на 8 позицию.

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

Лично я не согласен с данной статистикой, потому что буквально за последние два года находил много CSRF-уязвимостей. Дальше я расскажу, как я это делал.

В классификации Bugcrowd VRT (Vulnerability Rating Taxonomy) Application-wide CSRF-уязвимости имеют рейтинг severity P2 (High). Выше только severity critical, то есть это достаточно серьезные уязвимости.
oh2plvuhqczibq9rm4lmogh1ugi.jpeg

Рассмотрим, какие варианты защиты от CSRF существуют и как работает каждый из вариантов защиты.

1. CSRF token

  • Для каждой пользовательской сессии генерируется уникальный и высокоэнтропийный токен.
  • Токен вставляется в DOM HTML страницы или отдается пользователю через API.
  • Пользователь с каждым запросом, связанным с какими-либо изменениями, должен отправить токен в параметре или в HTTP-заголовке запроса.
  • Так как атакующий не знает токен, то классическая CSRF-атака не работает.


2. Double submit cookie

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


3. Content-Type based protection

  • Пользователь должен отправить запрос с определенным заголовком Content-Type, например, application/json.
  • Так как в браузере через HTML форму или XHR API невозможно отправить произвольный Content-Type cross-origin, то классическая CSRF-атака опять не работает.


4. Referer-based protection

  • Пользователь должен отправить запрос с определенным значением заголовка Referer. Бэкенд его проверяет, если он неверный, то считается, что это CSRF-атака.
  • Так как браузер не может отправить произвольный Referer через HTML форму или XHR API, то классическая CSRF-атака не работает.


5. Password confirmation / websudo

  • Пользователь должен подтверждать действие с помощью пароля (или секрета).
  • Так как атакующий его не знает, то классическая CSRF-атака не работает.


6. SameSite Cookies в Chrome, Opera
Это новая технология, которая призвана защитить от CSRF. В данный момент она работает только в двух браузерах (Chrome, Opera).

  • У куки устанавливается дополнительный атрибут — samesite, который может иметь два значения: lax или strict.
  • Суть технологии в том, что браузер не отправляет куки, если запрос осуществляется с другого домена, например, с сайта атакующего. Таким образом это опять защищает от классической CSRF-атаки.


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

Поэтому, теперь давайте поговорим о 8 способах обхода защиты, которые можно использовать на практике.
fhtkrxcjtbvw2mfyxctik-zqizc.jpeg

Сценарии обхода:


1. XSS (cross-sitescripting)

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

2. Dangling markup

Допустим, в нашем приложении есть уязвимость к HTML injection, но нет XSS. Например, есть Content Security Policy (CSP), которая защищает от XSS. Но атакующий все равно может внедрять HTML теги.

Если в нашем приложении реализована защита, основанная на CSRF-токенах, атакующий может внедрить такой HTML, это не закрытые теги image или form: