Достаточно ли проверки сервера заголовков X-Requested-With для защиты от CSRF для приложения, управляемого Ajax? - PullRequest
24 голосов
/ 23 июля 2010

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

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

Это обычнодостаточно для защиты от подделки межсайтовых запросов?

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

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

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

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

Ответы [ 6 ]

14 голосов
/ 26 июля 2010

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

Статический токен не очень хорошая идея. Токен должен генерироваться как минимум один раз за сеанс.

EDIT2 Майк, в конце концов, не прав, извините. Я не прочитал страницу, на которую я ссылался должным образом. Там написано:

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

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

РЕДАКТИРОВАТЬ Майк прав, начиная с Firefox 3.5, межсайтовые XMLHttp-запросы разрешены . Следовательно, вы также должны проверить, соответствует ли заголовок 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(); 
1 голос
/ 28 июня 2017
1 голос
/ 27 июля 2010

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

Также, чтобы предупредить комментарии о том, что XMLHttp не работает в скрипте. Я использовал следующий код с Firefox 3.5, чтобы сделать запрос к Google из HTML, работающего в локальном домене. Содержимое не будет возвращено, но, используя 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");

0 голосов
/ 26 июля 2010

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

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

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

0 голосов
/ 23 июля 2010

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

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

0 голосов
/ 23 июля 2010

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

...