Является ли сервер заголовка X-Requested-With достаточным для защиты от CSRF для приложения, управляемого ajax?
Я работаю над полностью управляемым ajax приложением, где все запросы проходят через то, что в основном составляет основной контроллер, который на его голой кости выглядит примерно так:
if(strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
fetch($page);
}
Как правило, это достаточно для защиты от подделок поддонов?
Это довольно неудобно иметь вращающийся токен, когда вся страница не обновляется с каждым запросом.
Я предполагаю, что могу передать и обновить уникальный токен как глобальную переменную javascript с каждым запросом, но так или иначе чувствует себя неуклюжим и в любом случае кажется небезопасным.
EDIT - Возможно, статический токен, такой как пользовательский UUID, будет лучше, чем ничего?
РЕДАКТИРОВАТЬ # 2 - Как заметил Ладья, это может быть вопрос, связанный с волосами. Я читал спекуляции в обоих направлениях и слышал отдаленные шепоты о более старых версиях флеш-памяти, которые можно использовать для таких махинаций. Поскольку я ничего не знаю об этом, я предлагаю щедрость всем, кто может объяснить, как это риск CSRF. В противном случае я отдаю его Артефакто. Спасибо.
Ответы
Ответ 1
Я бы сказал это достаточно. Если разрешены междоменные запросы, вы все равно обречены на то, что злоумышленник может использовать Javascript для извлечения токена CSRF и использовать его в поддельном запросе.
Статический токен - отличная идея. Маркер должен быть сгенерирован как минимум один раз за сеанс.
EDIT2 Майк не прав, извините. Я не читал связанную с ним страницу. В нем говорится:
Простой кросс-сайт-запрос - это тот, который: [...] Не устанавливает пользовательские заголовки с HTTP-запросом (например, X-Modified и т.д.).
Следовательно, если вы установите X-Requested-With
, запрос должен быть предварительно обработан, и если вы не ответите на запрос перед полетом OPTIONS
, разрешающий запрос на межсайтовый сайт, он не пройдет.
EDIT Майк прав, а с 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();
Ответ 2
Я не считаю, что это безопасно. Те же политики происхождения предназначены для предотвращения доступа документов из разных доменов к содержимому, которое возвращается из другого домена. Вот почему проблемы XSRF существуют в первую очередь. Вообще XSRF не заботится об ответе. Он используется для выполнения определенного типа запроса, например, для удаления.
В простейшей форме это можно сделать с правильно отформатированным тегом img. Ваше предлагаемое решение предотвратит эту простую форму, но не защитит кого-либо от использования объекта XMLHttp для запроса.
Вам необходимо использовать стандартные методы предотвращения XSRF. Мне нравится генерировать случайное число в javascript и добавлять его в файл cookie и переменную формы. Это гарантирует, что код также может записывать файлы cookie для этого домена. Если вы хотите получить дополнительную информацию, см. эту запись.
Кроме того, чтобы упредить комментарии о том, что XMLHttp не работает в script. Я использовал следующий код с 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");
Ответ 3
Да. Это признанный подход к защите CSRF.
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Protecting_REST_Services:_Use_of_Custom_Request_Headers
Ответ 4
Я не думаю, что это предлагает какую-либо защиту. Атакующий сайт все еще может использовать xmlhttprequest
для своего запроса на межсайтовый сайт в обход вашей проверки.
Ответ 5
Короткий ответ: нет. Любой злоумышленник просто использует Ajax для атаки вашего сайта.
Вы должны создать случайный токен с коротким, но не слишком большим сроком жизни, который вы обновляете во время каждого запроса ajax.
Вам нужно будет использовать массив токенов в javascript, так как вы можете одновременно запускать несколько запросов ajax.
Ответ 6
То, что вы делаете, безопасно, потому что xmlhttprequest обычно не уязвим для подделки подделок.
Поскольку это проблема на стороне клиента, самым безопасным способом было бы проверить архитектуру безопасности каждого браузера: -)
(Это резюме, я добавляю этот ответ, потому что этот вопрос очень запутан, давайте посмотрим, что говорят голоса)