Поэтому я читаю и действительно смущен тем, что у меня есть токен CSRF, и я должен генерировать новый токен за каждый запрос или только час или что-то еще?
$data['token'] = md5(uniqid(rand(), true)); $_SESSION['token'] = $data['token'];
Но предположим, что лучше генерировать токен каждый час, тогда мне потребуются две сессии: токен, истечение,
И как я буду приступать к форме? Просто поместите echo $ _SESSION ['токен'] в форму скрытого значения, а затем сравните на submit?
Если вы делаете это по запросу формы – тогда вы в основном удаляете возможность для атак CSRF, и вы можете решить еще одну общую проблему: множественная подача формы
Простыми словами – ваше приложение будет принимать только ввод формы, если пользователь запросил форму до подачи.
Обычный сценарий: пользователь A отправляется на ваш сайт и запрашивает форму A, получает форму A плюс уникальный код для формы A. Когда пользователь отправляет форму A, он должен включать уникальный код, который был только для формы A.
CSRF Attack: Пользователь A отправляется на ваш сайт и просит Form A. Между тем они посещают другой «плохой» сайт, который пытается атаковать CSRF на них, заставляя их отправлять фальшивую форму B.
Но ваш сайт знает, что пользователь A никогда не запрашивал форму B, и поэтому, хотя у них есть уникальный код для формы A, форма B будет отклонена, потому что у них нет уникального кода формы B, а только код формы A. Ваш пользователь в безопасности, и вы можете спокойно спать по ночам.
Но если вы сделаете это как общий токен, продержавшись в течение часа (например, вы разместили выше) – тогда может произойти атака выше, и в этом случае вы не достигли большого успеха с вашей защитой CSRF. Это связано с тем, что приложение не знает, что форма B никогда не запрашивалась в первую очередь. Это общий токен. ВЕСЬ ТОЧКА CSRF-профилактики состоит в том, чтобы сделать каждый маркер формы уникальным для этой формы
Изменить: поскольку вы запросили дополнительную информацию: 1 – вам не нужно делать это в запросе формы, вы можете делать это в час / сеанс и т. Д. Точка – это секретное значение, которое предоставляется пользователю, и повторно отправляется по возврату. Это значение не известно другому веб-сайту и, следовательно, не может представить ложную форму.
Таким образом, вы либо генерируете токен для каждого запроса, либо за сеанс:
// Before rendering the page: $data['my_token'] = md5(uniqid(rand(), true)); $_SESSION['my_token'] = $data['my_token']; // During page rendering: <input type="hidden" name="my_token" id="my_token" value="<? php echo $_SESSION['my_token']?>" /> // After they click submit, when checking form: if ($_POST['my_token'] === $_SESSION['my_token']) { // was ok } else { // was bad!!! }
и потому что это «за форму» – вы не получите двойных представлений – потому что вы можете стереть токен после подачи первой формы!
Как правило, достаточно одного токена для пользователя или сеанса. Важно, чтобы токен привязывался только к одному конкретному пользователю / сеансу, а не к глобальному использованию.
Если вы боитесь, что токен может просочиться или получить полученный атакующий сайт (например, XSS), вы можете ограничить срок действия токена до определенного таймфрейма, определенной формы / URL-адреса или определенного количества применений.
Но ограничение действительности имеет недостаток, что это может привести к ложным срабатываниям и, следовательно, ограничениям в удобстве использования, e. г. законный запрос может использовать токен, который был просто недействителен, поскольку запрос токена слишком давно, или токен уже используется слишком часто.
Поэтому моя рекомендация – просто использовать один токен на пользователя / сеанс. И если вам нужна дополнительная безопасность, используйте один токен для каждой формы / URL-адреса для каждого пользователя / сеанса, чтобы, если токен для одной формы / URL-адреса просочился, остальные все еще безопасны.
Ответ на ваш вопрос: это зависит.
И вам не нужно использовать сеанс для временных токенов, вы можете просто использовать серверное время и секретный ключ на сервере.
Но предположим, что лучше генерировать токен каждый час, тогда мне потребуются две сессии: токен, истечение,
Нет, вам нужна процедура, которая может генерировать токен для временного кадра. Допустим, вы делите время на 30 минут. Вы создаете один токен за текущие 30 минут в форме.
Когда будет отправлена форма, и вы проверите токен против на данный момент и против предыдущего 30-минутного периода. Поэтому токен действителен в течение 30 минут до одного часа.
$token = function($tick = 0) use($secret, $hash) { $segment = ((int) ($_SERVER['REQUEST_TIME'] / 1800)) + $tick; return $hash($secret . $segment); };
Вы можете использовать оба метода.
1) Случайный токен для каждого запроса. Чтобы решить проблему несинхронизированных токенов, вы можете использовать серверные события http://www.w3.org/TR/eventsource/ или websockets http://www.w3.org/TR/websockets/ comunication для обновления токены в режиме реального времени для каждой страницы.
2) Вы можете использовать токен на сеанс пользователя (не нужно делать его в час), который проще реализовать. У вас не будет проблем с синхронизацией, но если токен не слишком силен, его можно догадаться. Ofcorse, если токен очень случайный, для ненаправленного человека будет очень сложно фактически выполнить подделку запроса.
Первый метод PS является самым безопасным, но его сложнее реализовать и использовать больше ресурсов.