Сен 30 2008
Защита сайта от cross-site request forgery (CSRF)
Cross-site request forgery — это разновидность атаки на пользователя, при которой посещаемый веб-сайт выполняет несанкционированные действия, используя действующую авторизацию.
Предположим Вы зашли на сайт A, авторизовались там как пользователь (используя куки) и не завершая сессии зашли на сайт B, который использует CSRF-уязвимость сайта A и выполняет от Вашего имени какие-либо действия, например, постит сообщение, содержащее спам, поднимает репутацию какому-нибудь пользователю или что-нибудь еще в таком духе. А может быть еще и вот такой забавный сценарий, который некогда воплотился на сайте вконтакте.ру.
Прежде чем продолжить, хочу сразу сделать оговорку. CSRF — это в общем понимании не совсем уязвимость. Уязвимость — это когда при каких-то определенных условиях программа ведет себя не так, как задумывал ее разработчик. Но CSRF — это нормальное поведение всех сайтов в Интернете! Это можно сказать фича Интернета, которая иногда может быть использована во вред.
Суть в том, что форма и обработчик формы не обязаны находиться на одном и том же сайте. Обработчик формы обработает пришедший к нему запрос с данными вне зависимости от того, с какого адреса они пришли.
Иногда это бывает удобно. Например, мне как-то раз надоело вручную заполнять одни и те же заявки на неисправность у провайдера КабiNET и я на локалхосте создал форму один в один повторяющую поля и указал в качестве обработчика (action) обработчик на сайте провайдера. В результате, у меня была своя форма заявки, в которой уже были заведены основные шаблоны описаний неисправностей, нужно было лишь выбрать шаблон и нажать Отправить.
Это был пример мирного применения CSRF, но существуют естественно и враждебные, защиту от которых должен предусмотреть разработчик сайта. Ситуация осложняется тем, что враждебный сайт может использовать Javascript, чтобы произвести отправку формы (без всяких кликов, неважно GET или POST) в невидимом IFrame’е так, что пользователь даже не будет знать о том, что от его имени где-то что-то выполнилось. Страшно?
Как же защититься от враждебного применения CSRF?
В примитиве обработчик формы может просто проверять HTTP-заголовок Referer, где указывается с какого адреса пришел запрос и если адрес левый, то не обрабатывать запрос. Но этот заголовок не является обязательным и некоторые файрволлы (я точно знаю, что Agnitum Outpost Firewall) подменяют значение этого заголовка на название или адрес сайта файрволла. Поэтому полагаться на Referer все же не стоит.
Более грамотным решением является встраивание в форму дополнительного скрытого поля, содержащее какое-то значение, зависящее от текущей сессии пользователя. Самое простое и первое что приходит в голову — естественно идентификатор сессии. Враждебный сайт не сможет прочитать куку другого сайта (см. same origin policy) и соответственно не сможет подставить в скрытое поле правильное значение.
Используйте описанный прием всегда там, где теоретически возможно враждебное применение CSRF.
См. также описание CSRF на википедии.

Ноябрь 13th, 2008 at 21:58
cookies приходят серверу и без данных формы.
может при обработке данных формы просто проверять валидность сессии?
Ноябрь 21st, 2008 at 12:46
Нет, Макс! Сессия-то у тебя всегда будет валидной. Нам нужно удостовериться в том, что данные пришли не с сайта xxx.com, в котором форма отправлялась javascript’ом через невидимый iframe, а с нашего сайта. И дополнительный избыточный код в форме — это что-то вроде упрощенного варианта цифровой подписи самой формы, и этот код подтверждает: “эти данные отправлены с формы, расположенной на том же домене”. Потому что другой сервер на другом домене просто не смог бы получить ID сессии нашего сайта. Вот и все!
Ноябрь 21st, 2008 at 17:15
с тобой невозможно не согласиться - зришь в корень)))
Декабрь 2nd, 2008 at 20:47
Есть редкое исключение, при котором браузер позволяет AJAX’у запросить удалённую страницу с “чужого” домена. В таком случае можно прочитать имя сессии в форме и не только! Подбробно уже написано добрыми людьми тут:
http://www.inattack.ru/article/552.html
Декабрь 2nd, 2008 at 21:03
То, что IE позволяет отправлять запрос аяксом на чужой сайт — это его уязвимость, но я очень сомневаюсь, что через XMLHTTPRequest можно получить еще и cookie с другого домена. И google вроде как тоже говорит, что нельзя.
Декабрь 2nd, 2008 at 21:51
Я имел в виду не куки, а значение скрытого поля, в котором предполагается хранить SID.
Капча + SID + повторный ввод пароля спасут мир!