Как правильно добавить токен CSRF с помощью PHP
Я пытаюсь добавить некоторую безопасность в формы на моем сайте. Одна из форм использует AJAX, а другая-это простая форма "свяжитесь с нами". Я пытаюсь добавить токен CSRF. Проблема, с которой я сталкиваюсь, заключается в том, что токен появляется только в HTML "value" некоторое время. В остальное время значение пусто. Вот код, который я использую в форме AJAX:
PHP:
if (!isset($_SESSION)) {
session_start();
$_SESSION['formStarted'] = true;
}
if (!isset($_SESSION['token']))
{$token = md5(uniqid(rand(), TRUE));
$_SESSION['token'] = $token;
}
HTML
<form>
//...
<input type="hidden" name="token" value="<?php echo $token; ?>" />
//...
</form>
какие предложения?
3 ответов:
Предупреждение:
md5(uniqid(rand(), TRUE))не является безопасным способом для генерации случайных чисел. Смотрите ответ для получения дополнительной информации и решение, которое использует криптографически безопасный генератор случайных чисел.Похоже, вам нужно еще с вашим if.
if (!isset($_SESSION['token'])) { $token = md5(uniqid(rand(), TRUE)); $_SESSION['token'] = $token; $_SESSION['token_time'] = time(); } else { $token = $_SESSION['token']; }
для кода безопасности, пожалуйста, не создавайте свои токены таким образом:
$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'];Примечание: один из мой работодатель проекты с открытым исходным кодом это инициатива по backport
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 templating engine может воспользуйтесь упрощенной двойной стратегией, добавив этот фильтр в свою среду веточек:
$twigEnv->addFunction( new \Twig_SimpleFunction( 'form_token', function($lock_to = null) { if (empty($_SESSION['token'])) { $_SESSION['token'] = bin2hex(random_bytes(32)); } if (empty($_SESSION['token2'])) { $_SESSION['token2'] = random_bytes(32); } if (empty($lock_to)) { return $_SESSION['token']; } return hash_hmac('sha256', $lock_to, $_SESSION['token2']); } ) );С помощью этой функции веточки вы можете использовать как токены общего назначения, так и:
<input type="hidden" name="token" value="{{ form_token() }}" />или заблокированный вариант:
<input type="hidden" name="token" value="{{ form_token('/my_form.php') }}" />Twig связан только с визуализацией шаблона; вы все равно должны правильно проверить маркеры. На мой взгляд, стратегия Twig предлагает большую гибкость и простоту, сохраняя при этом возможность для максимального безопасность.
одноразовые токены CSRF
если у вас есть требование безопасности, чтобы каждый токен CSRF можно было использовать ровно один раз, самая простая стратегия регенерирует его после каждой успешной проверки. Однако это приведет к недействительности каждого предыдущего токена, который не очень хорошо сочетается с людьми, которые просматривают сразу несколько вкладок.
Paragon Initiative Enterprises поддерживает библиотека анти-CSRF для этих случаев углу. Оно работает исключительно с одноразовыми токенами для каждой формы. Когда в данных сеанса будет сохранено достаточное количество токенов (конфигурация по умолчанию: 65535), сначала будут задействованы самые старые неиспользованные токены.
Comments