Является ли сервер заголовка X-Requested-With достаточным для защиты от CSRF для приложения, управляемого ajax?

Я работаю над полностью управляемым ajax приложением, где все запросы проходят через то, что в основном составляет основной контроллер, который на его голой кости выглядит примерно так:

if(strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { fetch($page); } 

Достаточно ли этого для защиты от подделок подпроса?

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

Я полагаю, что я мог бы передавать и обновлять уникальный токен как глобальную переменную javascript с каждым запросом, но так или иначе чувствует себя неуклюжим и, по-видимому, по своей сути является небезопасным.

EDIT. Может быть, статический токен, такой как UUID пользователя, будет лучше, чем ничего?

РЕДАКТИРОВАНИЕ № 2 – Как отметила Ладья , это может быть вопрос, связанный с волосами. Я читал спекуляции в обоих направлениях и слышал отдаленные шепоты о более старых версиях флеш-памяти, которые можно использовать для таких махинаций. Поскольку я ничего не знаю об этом, я предлагаю щедрость всем, кто может объяснить, как это риск CSRF. В противном случае я отдаю его Артефакто . Благодарю.

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

Статический токен – отличная идея. Маркер должен генерироваться не реже одного раза в сеанс.

EDIT2 Майк не прав, извините. Я не читал связанную с ним страницу. В нем говорится:

Простой межсайтовый запрос – это тот, который: […] Не устанавливает пользовательские заголовки с HTTP-запросом (например, X-Modified и т. Д.),

Поэтому, если вы установите X-Requested-With , запрос должен быть предварительно обработан, и если вы не ответите на запрос перед полетом OPTIONS разрешающий запрос на межсайтовый сайт, он не пройдет.

EDIT Mike прав, с Firefox 3.5 разрешены межсайтовые XMLHttpRequests. Следовательно, вы также должны проверить, соответствует ли заголовок Origin , когда он существует, ваш сайт.

 if (array_key_exists('HTTP_ORIGIN', $_SERVER)) { if (preg_match('#^https?://myserver.com$#', $_SERVER['HTTP_ORIGIN']) doStuff(); } elseif (array_key_exists('HTTP_X_REQUESTED_WITH', $_SERVER) && (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest')) doStuff(); 

Я не верю, что это безопасно. Те же политики происхождения предназначены для предотвращения доступа документов из разных доменов к содержимому, которое возвращается из другого домена. Вот почему проблемы XSRF существуют в первую очередь. Вообще XSRF не заботится об ответе. Он используется для выполнения определенного типа запроса, например, для удаления. В простейшей форме это можно сделать с правильно отформатированным тегом img. Ваше предлагаемое решение предотвратит эту простую форму, но не защитит кого-либо от использования объекта XMLHttp для запроса. Вам необходимо использовать стандартные методы предотвращения XSRF. Мне нравится генерировать случайное число в javascript и добавлять его в файл cookie и переменную формы. Это гарантирует, что код также может записывать файлы cookie для этого домена. Если вы хотите получить дополнительную информацию, пожалуйста, ознакомьтесь с этой записью .

Кроме того, чтобы упредить комментарии о том, что XMLHttp не работает в скрипте. Я использовал следующий код с firefox 3.5, чтобы сделать запрос на google из html, запущенного в домене localhost. Содержимое не будет возвращено, но с использованием firebug вы можете увидеть, что запрос выполнен.

 <script> var xmlhttp = false; if (!xmlhttp && typeof XMLHttpRequest != 'undefined') { try { xmlhttp = new XMLHttpRequest(); } catch (e) { xmlhttp = false; } } if (!xmlhttp && window.createRequest) { try { xmlhttp = window.createRequest(); } catch (e) { xmlhttp = false; } } xmlhttp.open("GET", "http://www.google.com", true); xmlhttp.onreadystatechange = function() { if (xmlhttp.readyState == 4) { alert("Got Response"); alert(xmlhttp.responseText) } } xmlhttp.send(null) alert("test Complete"); 

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

Короткий ответ: нет. Любой злоумышленник просто использует Ajax для атаки вашего сайта. Вы должны создать случайный токен с коротким, но не слишком большим сроком жизни, который вы обновляете во время каждого запроса ajax.

Вам нужно будет использовать массив токенов в javascript, так как вы можете одновременно запускать несколько запросов ajax.

То, что вы делаете, безопасно, потому что xmlhttprequest обычно не уязвим для подделки подпроса.

Поскольку это проблема на стороне клиента, самым безопасным способом было бы проверить архитектуру безопасности каждого браузера 🙂

(Это резюме, я добавляю этот ответ, потому что этот вопрос очень запутан, давайте посмотрим, что говорят голоса)