Генерация токена CSRF - PullRequest
       47

Генерация токена CSRF

42 голосов
/ 27 ноября 2009

Это вопрос о генерации токенов CSRF.

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

Мой вопрос касается генерации токенов, когда НЕТ уникальных пользовательских данных для использования. Сеансы недоступны, файлы cookie недоступны, IP-адрес и тому подобное не являются надежными.

Есть ли причина, по которой я не могу также включить строку в хеш как часть запроса? Пример псевдокода для генерации токена и его вставки:

var $stringToHash = random()
var $csrfToken = hash($stringToHash + $mySecretKey)
<a href="http://foo.com?csrfToken={$csrfToken}&key={$stringToHash}">click me</a>

Пример проверки на стороне сервера токена CSRF

var $stringToHash = request.get('key')
var $isValidToken = hash($stringToHash + $mySecrtKey) == request.get('csrfToken')

Строка, используемая в хэше, будет отличаться при каждом запросе. Пока он был включен в каждый запрос, проверка токена CSRF могла продолжаться. Поскольку он является новым для каждого запроса и внедряется только на странице, внешний доступ к токену будет недоступен. Безопасность токена падает до того, что $ mySecretKey известен только мне.

Это наивный подход? Я скучаю по какой-то причине, почему это не может работать?

Спасибо

Ответы [ 8 ]

28 голосов
/ 04 декабря 2009

Есть ли причина, по которой я не могу включить строку в хеш как часть запроса?

Жетоны CSRF состоят из двух частей. Токен, встроенный в форму, и соответствующий токен где-то еще, будь то в файле cookie, хранящийся в сеансе или где-либо еще. Это использование в другом месте останавливает самодостаточность страницы.

Если вы включите строку для хеширования в запрос, то запрос будет самодостаточным, поэтому злоумышленнику необходимо скопировать форму, поскольку у него есть обе части токена, и, следовательно, защита отсутствует. 1007 *

Даже если поместить его в URL-адрес формы, это означает, что он самодостаточен, злоумышленник просто скопирует форму и URL-адрес отправки.

7 голосов
/ 31 мая 2013

Попробуйте base64_encode(openssl_random_pseudo_bytes(16)). https://github.com/codeguy/php-the-right-way/issues/272#issuecomment-18688498, и я использовал это для моего примера формы в https://gist.github.com/mikaelz/5668195

2 голосов
/ 27 ноября 2009

CSRF-токен, предназначенный для предотвращения (непреднамеренных) изменений данных, которые обычно применяются к запросам POST.

Таким образом, вы должны включать токен CSRF для каждого запроса, который изменяет данные (запрос GET или POST).

Мой вопрос касается генерирование токенов, когда НЕТ уникальные пользовательские данные для использования. Нет сессий файлы cookie не являются вариант, IP-адрес и тому подобное природа ненадежна.

Затем просто создайте уникальный идентификатор пользователя для каждого посетителя. Включите этот идентификатор в файл cookie или в URL (если файлы cookie отключены).

Edit:

Рассмотрим следующее событие:

Вы вошли в свою учетную запись Facebook, а затем вошли на какой-либо произвольный веб-сайт.

На этом веб-сайте вы отправляете форму, в которой ваш браузер отправляет запрос POST на вашу учетную запись Facebook.

Этот запрос POST может изменить ваш пароль или добавить комментарий и т. Д., Поскольку приложение facebook распознало вас как зарегистрированного и вошедшего в систему пользователя. (если нет другого блокирующего механизма, такого как CAPTCHA)

1 голос
/ 31 мая 2018

Существует несколько реализаций токена CSRF. Главное, генерируется ли этот токен csrf на стороне клиента или на стороне сервера. Потому что реализация резко меняется для этих двух сценариев, а также для энтропии токена.

Для серверной стороны SecureRandom является предпочтительным способом, но в вашем случае вы хотите сгенерировать токен CSRF до того, как будет идентифицирован какой-либо пользователь, window.crypto предоставляет эту функцию, где вы можете сгенерировать неузнаваемый достаточно строки для использования в качестве токена CSRF.

1 голос
/ 05 марта 2010

Вам просто нужен один и тот же «токен» в URL / форме и в куки. Это означает, что ваша страница может установить для cookie-файла токена все, что захочет (предпочтительно какое-то случайное значение) с помощью JavaScript, а затем просто передать одно и то же значение во всех запросах, отправляемых на ваш сервер (в виде параметра или формы URI? поле). Не нужно, чтобы ваш сервер генерировал куки.

Это безопасно, если мы уверены, что браузер не позволяет страницам из домена редактировать / читать файлы cookie для других доменов, и сегодня это считается достаточно безопасным.

Если ваш сервер генерирует токен, он будет предполагать, что этот токен может быть безопасно передан в ваш браузер без каких-либо попыток CSRF (зачем рисковать?). Хотя можно добавить больше логики в токен, сгенерированный сервером, но для предотвращения CSRF в этом нет необходимости.

(Если я не прав, пожалуйста, дайте мне знать)

0 голосов
/ 19 октября 2014

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

Таким образом, есть два ключевых фактора защиты CSRF

  1. Сгенерируйте токен запроса и потребуйте, чтобы клиент передал его на сервер без использования cookie-файлов. Можно использовать параметр URL или форму POST.
  2. Храните токен в безопасности, как то, что вы сделали с SessionID, например, используя SSL.

Я рекомендую прочитать Шпаргалка по профилактике CSRF

0 голосов
/ 27 марта 2012

Я думаю, что лучшая идея сделать хеш на основе HMAC, то есть сделать хеш, зашифрованный паролем, в такой последовательности: username + user_id + timestamp. Каждый запрос хеш должен быть разным, отметка времени должна быть, если вы не хотите, чтобы просто воспроизвести хэш в атаке.

0 голосов
/ 04 декабря 2009

CSRF использует сеанс пользователя, поэтому, если у вас его нет, CSRF отсутствует.

...