PHP сессия конфликтует с AJAX - PullRequest
0 голосов
/ 25 января 2011

код говорит тысячу слов

page.php? Id = 123

<?php
if(is_ajax()){// function that determines whether the request is from ajax (http header stuff)
$_SESSION['token'] = md5(rand());
}
//some ajax request to ajax.php?id=123
?>

ajax.php? Id = 123

<?php
if($_SESSION['token'] == $_GET['token']){
echo 'Tell me this is for reall';
}else{
echo 'Invalid Request';
}
?>

Все работает нормальнопока пользователь не откроет page.php? id = 456 на другой вкладке, ajax вернет 'недопустимый запрос' на page.php? id = 123 Как разрешить этот конфликт?

ps: если это возможно, я хочу новый сеанс для каждой страницы для целей CSRF

Ответы [ 3 ]

4 голосов
/ 25 января 2011

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

 if (isset($_SESSION['token'])){
    //do nothing
 } else{
   $_SESSION['token'] = md5(rand());
 }

Редактировать Чтобы ответить на ваш вопрос.

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

$_SESSION[$sessionId] = md5(rand());

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

например,

http://www.yoursite.com/somepage.php?sessionid=<some generated id>

В конечном счете, пользователь может с этим справиться, но я не уверен, что есть какой-то способ обойти это.

Редактировать 2 Хорошо, вот моя мысль о том, как вы должны это сделать.Эксперты по безопасности, не стесняйтесь меня обвинять, если я ошибаюсь, как я уже говорил, я не эксперт, но не похоже, что я выйду из этого, не предложив чего-либо; -)

Проблема с CSFR заключается в том, что какой-то злонамеренный пользователь, Боб, может создать элемент на другом сайте, который заставляет браузер Алисы сделать запрос на другой сайт, и потому что Алиса ранее вошла в систему и эта информация сохраняется либо какcookie или Алиса распознаются через сеанс, сайт выполняет запрос, как если бы Алиса запросила его.Например, если банк Алисы - http://www.mybank.com,, тогда Боб может создать сообщение на форуме, содержащее

<img srg="http://www.mybank.com/transferfunds.php?amount=1000&receiver=Bob" />

Банк Алисы распознает ее браузер как запрос, думая, что это она.Есть несколько ключевых вещей, которые должны произойти (вместе, каждое из которых приведет к провалу атаки), чтобы сделать это жизнеспособной атакой (вот ключевые для понимания того, как ее предотвратить):

  1. Алиса должна зайти на свой банковский сайт, чтобы банк ее запомнил.Это может произойти либо в файле cookie («запомнить меня»), либо в сеансе.Однако если она закроет свой браузер (завершит сеанс) или очистит файлы cookie, угрозы не будет, потому что сайт банка не узнает ее и отклонит запрос.
  2. Боб должен быть в состоянии предоставить всенеобходимые параметры для запроса, в противном случае веб-сайт банка отклонит запрос.

Чтобы дать некоторое представление о «состоянии» поверх протокола без учета состояния (HTTP), вы действительно не можетеобойти риск в (1).Если вы не заставите людей всегда нажимать кнопку «Выйти» или закрыть окно и т. Д., Вы ничего не сможете сделать, храня информацию в браузере или сеансе.Однако вы можете предотвратить возникновение проблемы (2).Мое решение этого (и я уверен, что есть множество других) состоит в том, чтобы сгенерировать хеш, как вы делаете, и сохранить его в сеансе.

Например,

$_SESSION['token'] = md5(rand());

Затем вы добавляете этот токен ко всем внутренним ссылкам.

http://www.mysite.com/secure.php?token=giuwnrefviunslfghahgliuwnvwrgbaasd

Вы НИКОГДА сохранить этот токен в памяти браузера: то есть, cookie.Когда поступают запросы, прежде чем что-либо делать, вы проверяете токен

//note, you'll want to sanitize user input, I'm just being brief
if ($_GET['token'] != $_SESSION['token']){
   //User either attempted to enter a link on their own or it's a CSRF attack
   header('HTTP/1.1 403 Forbidden');
 }else{
 //do whatever needs to be done
 }

Ключом к этому является то, что все ссылки на вашем сайте будут включать токен.Однако у Боба нет возможности узнать, что это за токен, потому что он не хранится в cookie в браузере.Если он попытается создать ссылку на одну из ваших страниц, она либо будет содержать неправильный ключ, либо не будет содержать какой-либо ключ, и вы можете отрицать это.(Чтобы быть справедливым, есть шанс, что он мог правильно угадать токен для конкретного пользователя, который случайно просматривает свой код, но он, вероятно, с большей вероятностью загорелся.)

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

1 голос
/ 25 января 2011

Что вы пытаетесь сделать? Можем ли мы увидеть JavaScript?

Похоже, вы установили токен сеанса в случайный хэш, а затем позже проверили его. Таким образом, если пользователь дважды открывает страницу, он снова рандомизируется и делает недействительным предыдущий токен. Какое поведение вы ожидаете?

0 голосов
/ 25 января 2011

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

<?php
if(is_ajax()){// function that determines whether the request is from ajax (http header stuff)
$page_id = $_GET['id'];
$_SESSION['token'][$page_id] = md5(rand());
}
//some ajax request to ajax.php?id=123
?>

и

<?php
$page_id = $_GET['id'];
if($_SESSION['token'][$page_id] == $_GET['token']){
echo 'This is for real!';
}else{
echo 'Invalid Request';
}
?>

В зависимости от того, как именно вы реализуете все, вам, вероятно, потребуется что-то более сложное или специализированное, но это должно помочь вам начать работу.

...