Ответ 1
Для кода безопасности не генерируйте эти жетоны следующим образом: $token = md5(uniqid(rand(), TRUE));
-
rand()
является предсказуемым -
uniqid()
добавляет до 29 бит энтропии -
md5()
не добавляет энтропии, он просто смешивает его детерминистически
Попробуйте следующее:
Создание токена CSRF
PHP 7
session_start();
if (empty($_SESSION['token'])) {
$_SESSION['token'] = bin2hex(random_bytes(32));
}
$token = $_SESSION['token'];
Sidenote: один из моих проектов с открытым исходным кодом моего работодателя - это инициатива по обращению random_bytes()
и random_int()
в проекты PHP 5. Он MIT лицензирован и доступен в Github и Composer как paragonie/random_compat.
PHP 5.3+ (или с ext-mcrypt)
session_start();
if (empty($_SESSION['token'])) {
if (function_exists('mcrypt_create_iv')) {
$_SESSION['token'] = bin2hex(mcrypt_create_iv(32, MCRYPT_DEV_URANDOM));
} else {
$_SESSION['token'] = bin2hex(openssl_random_pseudo_bytes(32));
}
}
$token = $_SESSION['token'];
Проверка токена CSRF
Не используйте только ==
или даже ===
, используйте hash_equals()
(только PHP 5.6+, но доступный ранее версии с библиотекой hash-compat).
if (!empty($_POST['token'])) {
if (hash_equals($_SESSION['token'], $_POST['token'])) {
// Proceed to process the form data
} else {
// Log this as a warning and keep an eye on these attempts
}
}
Далее с использованием токенов в одной форме
Вы также можете ограничить токены только доступными для конкретной формы, используя hash_hmac()
. HMAC - это особая ключевая хеш-функция, которая безопасна в использовании даже при более слабых хеш-функциях (например, MD5). Тем не менее, я рекомендую использовать семейство хеш-функций SHA-2.
Во-первых, сгенерируйте второй токен для использования в качестве ключа HMAC, а затем используйте для этого такую логику:
<input type="hidden" name="token" value="<?php
echo hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
?>" />
И затем используя конгруэнтную операцию при проверке токена:
$calc = hash_hmac('sha256', '/my_form.php', $_SESSION['second_token']);
if (hash_equals($calc, $_POST['token'])) {
// Continue...
}
Токены, сгенерированные для одной формы, не могут быть повторно использованы в другом контексте, не зная $_SESSION['second_token']
. Важно, чтобы вы использовали отдельный токен в качестве ключа HMAC, чем тот, который вы просто запустили на странице.
Бонус: гибридный подход + интеграция Twig
Любой, кто использует
Или заблокированный вариант:
<input type="hidden" name="token" value="{{ form_token('/my_form.php') }}" />
Twig касается только рендеринга шаблона; вы все равно должны правильно проверить токены. По моему мнению, стратегия Twig обеспечивает большую гибкость и простоту, сохраняя при этом максимальную безопасность.
Одноразовые токены CSRF
Если у вас есть требование безопасности, чтобы каждый токен CSRF был доступен для использования ровно один раз, простейшая стратегия восстанавливает его после каждой успешной проверки. Однако это приведет к недействительности каждого предыдущего токена, который не будет хорошо сочетаться с людьми, которые просматривают сразу несколько вкладок.
Paragon Initiative Enterprises поддерживает анти-CSRF-библиотеку для этих угловых случаев. Он работает только с одноразовыми токенами для каждой формы. Когда в данных сеанса хранятся достаточное количество токенов (конфигурация по умолчанию: 65535), сначала будет выкачать самые старые неиспользуемые маркеры.