Я столкнулся с проблемой, связанной с токенами XSRF.
Клиент: Сервер AngularJS: PHP
Когда index.php попадает, PHP генерирует токен XSRF и сохраняет его в сеансе. Файл cookie устанавливается с одинаковым значением.
AngularJS считывает файл cookie и сохраняет значение.
При последующих POSTS токен XSRF отправляется как заголовок, и идея заключается в сравнении сохраненного токена сеанса с отправленным заголовком.
Все кажется прекрасным, никаких проблем.
НО: проблема в том, что PHP не может прочитать сеанс, зарегистрированный в index.php, потому что технически не было перезагрузок страниц! Если я удалю F5 и перезагрузим все, сеанс будет хорошо прочитан.
Как я могу установить токен сеанса XSRF на index.php и иметь его доступным для последующих запросов ajax от клиента? Я вытягиваю волосы на этом … ценю обратную связь.
ОБНОВИТЬ
После изменения имени идентификатора сеанса все неожиданно сработало!
В index.php:
// Create token and set session session_start(); $token = hash('sha256', uniqid(mt_rand(), true)); $_SESSION['XSRF']=$token;
Позже, также в index.php:
/* Give token to Angular client */ <script> angular.module("app").constant("CSRF_TOKEN", '<?=$_SESSION['XSRF'];?>'); </script>
Обратите внимание, что я не использую cookie, вместо этого устанавливаю константу, которая затем становится доступной для метода .run в Angular:
в Угловом:
angular.module('app').run(['CSRF_TOKEN','$http',function(CSRF_TOKEN,$http) { $http.defaults.headers.common['CSRF_TOKEN'] = CSRF_TOKEN;
Все запросы на сервер направляются в один общий файл php. Файл проверяет, установлен ли заголовок, и сравнивает два токена:
// Only POST requests are checked (I don't use PUT/DELETE) if($_SERVER['REQUEST_METHOD']=="POST"){ session_start(); $headerToken = $_SERVER['HTTP_CSRF_TOKEN']; $sessionToken = $_SESSION['XSRF']; if($headerToken!=$sessionToken){ header('HTTP/1.0 401 Unauthorized'); exit; } }
Это то, что я делаю в своих проектах PHP / AngularJS:
index.php
session_start(); if (!isset($_SESSION['XSRF-TOKEN'])) { $uniqueValues = md5($_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT']); //add more/less/any "unique" values, see comments $_SESSION['XSRF-TOKEN'] = sha1(uniqid(microtime() . $uniqueValues, true)); setcookie('XSRF-TOKEN', $_SESSION['XSRF-TOKEN']); }
любой скрипт, называемый AngularJS $ http:
(AngluarJS использует значение файла cookie XSRF-TOKEN и отправляет его в каждом запросе в качестве настраиваемого заголовка X-XSRF-TOKEN, поэтому нам нужно сравнить это значение со значением, хранящимся в сеансе.)
function verifyXSRF() { /* $headers = apache_request_headers(); $headerToken = ""; foreach ($headers as $header => $value) { if ($header == "X-XSRF-TOKEN") { $headerToken = $value; break; } } */ //more efficient, see comments $headerToken = $_SERVER['HTTP_X_XSRF_TOKEN']; if ($headerToken != $_SESSION['XSRF-TOKEN']) return false; return true; } session_start(); if (!verifyXSRF()) die("XSRF error");
Обратная связь приветствуется, поскольку я точно не знаю, достаточно ли XSRF-защиты.