Рассмотрим этот пример
index.php:
<script>
var first = new XMLHttpRequest();
var second = new XMLHttpRequest();
first.open('POST', 'foo.php');
second.open('POST', 'bar.php');
first.onreadystatechange = function()
{
console.log(document.cookie);
});
first.send();
second.send();
</script>
foo.php:
<?php
setcookie('foo', 'foo');
sleep(5);
bar.php:
<?php
setcookie('foo', 'bar');
Есть ли способ сделать foo == 'bar'
в куки, когда оба запроса заканчиваются, вместо foo == 'foo'
?
Изменить: я полагаю, мне нужно уточнить, почему это проблема.
Я пытаюсь реализовать библиотека предотвращать подделка межсайтовых запросов на моем сайте. Эта библиотека требует, чтобы уникальный токен был отправлен вместе с любым POST
запрос от клиента. Для этого библиотека сохраняет ожидаемый токен в SESSION
а затем отправляет токен в браузер, используя setcookie
,
Это проблема для меня, потому что я использую пользовательское хранилище сеансов, которое представляет собой таблицу в базе данных MySQL. Если два POST
запросы поступают от одного и того же клиента в течение достаточно короткого времени, это создает условие состязания, при котором ожидаемое значение в базе данных для третьего запроса всегда является токеном, сгенерированным запросом, отправленным последним, но токеном, используемым браузером из запроса, который ЗАВЕРШАЕТ последний. Если для выполнения запроса 1 требуется больше времени, чем для запроса 2, файл cookie и база данных не соответствуют запросу 3.
Вот почему я задал этот конкретный вопрос. я знаю это header
в PHP немедленно отправляет любую информацию заголовка в браузер, независимо от буферизации вывода, а куки по сути являются просто заголовками. Почему же я не могу принудительно применить это поведение с помощью файлов cookie?
Я понимаю, что всего этого можно было бы избежать, не отправляя несколько запросов так близко друг к другу, но у меня нет возможности изменить это в любое разумное количество времени, и просто постановка в очередь запросов на отправку только после предыдущего завершения будет отрицательно повлиять на опыт моих пользователей совсем немного.
Прежде всего, токен для предотвращения CSRF не должен изменять каждый запрос, поэтому я не уверен, почему это проблема. Просто сгенерируйте токен при входе в систему и придерживайтесь его.
Что еще более важно, Cookie не помешает CSRF потому что куки отправляются на поддельные запросы тоже! Это не профилактика CSRF. Вы должны отправить этот токен с данными POST, как правило, как скрытое поле в форме.
Кроме того, PHP уже предотвращает состояние гонки в том же сеансе по умолчанию. Если скрипт пытается session_start()
сеанс, который уже используется другим сценарием, он будет находиться в спящем режиме, пока не завершится другой вызов, или не вызовет session_write_close()
,
Боюсь, ответ на ваш оригинальный вопрос довольно прост: нет. Вы не обладаете достаточным контролем над соединениями, чтобы что-либо применять. Когда вы пишете в своем редактировании, настройка файлов cookie выполняется через заголовки, и это происходит асинхронно.
Что касается вашего отредактированного вопроса: вы можете сделать эту работу, сохранив несколько токенов для каждого клиента. То есть каждый раз, когда приходит новый запрос от клиента, не удаляйте текущий токен, а только создавайте новый. Клиентская сторона должна затем отправлять не только правильный токен, но и правильный «идентификатор соединения». Этот идентификатор может быть просто счетчиком количества запросов от клиента.
Кроме того, вы можете не обновлять токен для запросов AJAX, а только для обычной загрузки страниц. В зависимости от того, как работает ваш сайт, это может быть небезопасно.