formulario form example php security session csrf

form - Cómo agregar correctamente token CSRF usando PHP



php form token (4)

Estoy tratando de agregar algo de seguridad a los formularios en mi sitio web. Uno de los formularios usa AJAX y el otro es un formulario directo de "contáctenos". Estoy tratando de agregar un token CSRF. El problema que tengo es que el token solo aparece en el "valor" HTML algunas veces. El resto del tiempo, el valor está vacío. Aquí está el código que estoy usando en el formulario 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>

¿Alguna sugerencia?


Advertencia de seguridad : md5(uniqid(rand(), TRUE)) no es una forma segura de generar números aleatorios. Consulte esta respuesta para obtener más información y una solución que aprovecha un generador de números aleatorios criptográficamente seguro.

Parece que necesitas otro con tu si.

if (!isset($_SESSION[''token''])) { $token = md5(uniqid(rand(), TRUE)); $_SESSION[''token''] = $token; $_SESSION[''token_time''] = time(); } else { $token = $_SESSION[''token'']; }


En page.php

session_start(); if (empty($_SESSION[''token''])) { $_SESSION[''token''] = bin2hex(random_bytes(32)); } $token = $_SESSION[''token''];

En verification.php

session_start(); if (empty($_SESSION[''token''])) { $_SESSION[''token''] = bin2hex(random_bytes(32)); } 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 } }


La variable $token no se recupera de la sesión cuando está allí


Para el código de seguridad, no genere sus tokens de esta manera: $token = md5(uniqid(rand(), TRUE));

Probar esto:

Generando un Token CSRF

PHP 7

session_start(); if (empty($_SESSION[''token''])) { $_SESSION[''token''] = bin2hex(random_bytes(32)); } $token = $_SESSION[''token''];

Nota: Uno de los proyectos de fuente abierta de mi empleador es una iniciativa para random_bytes() y random_int() en proyectos de PHP 5. Está licenciado por MIT y está disponible en Github y Composer como paragonie/random_compat .

PHP 5.3+ (o con 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''];

Verificación del token CSRF

No use simplemente == o incluso === , use hash_equals() (PHP 5.6+ solamente, pero disponible para versiones anteriores con la biblioteca 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 } }

Ir más allá con fichas por formulario

Puedes restringir aún más los tokens para que estén disponibles solo para un formulario particular usando hash_hmac() . HMAC es una función hash con clave particular que es segura de usar, incluso con funciones hash más débiles (por ejemplo, MD5). Sin embargo, recomiendo usar la familia SHA-2 de funciones hash en su lugar.

Primero, genere un segundo token para utilizarlo como clave HMAC, luego use lógica como esta para representarlo:

<input type="hidden" name="token" value="<?php echo hash_hmac(''sha256'', ''/my_form.php'', $_SESSION[''second_token'']); ?>" />

Y luego usar una operación congruente al verificar el token:

$calc = hash_hmac(''sha256'', ''/my_form.php'', $_SESSION[''second_token'']); if (hash_equals($calc, $_POST[''token''])) { // Continue... }

Los tokens generados para un formulario no se pueden reutilizar en otro contexto sin saber $_SESSION[''second_token''] . Es importante que use un token separado como clave HMAC que el que acaba de colocar en la página.

Bonus: Enfoque Híbrido + Integración Twig

Cualquiera que use el motor de plantillas Twig puede beneficiarse de una estrategia doble simplificada agregando este filtro a su entorno Twig:

$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'']); } ) );

Con esta función Twig, puedes usar los dos tokens de propósito general así:

<input type="hidden" name="token" value="{{ form_token() }}" />

O la variante bloqueada:

<input type="hidden" name="token" value="{{ form_token(''/my_form.php'') }}" />

Twig solo se preocupa por la representación de la plantilla; aún debe validar los tokens correctamente. En mi opinión, la estrategia de Twig ofrece una mayor flexibilidad y simplicidad, manteniendo la posibilidad de la máxima seguridad.

Fichas CSRF de un solo uso

Si tiene un requisito de seguridad de que cada token CSRF puede usarse una sola vez, la estrategia más simple lo regenerará después de cada validación exitosa. Sin embargo, al hacerlo invalidará cada token anterior que no se combina bien con las personas que navegan por varias pestañas a la vez.

Paragon Initiative Enterprises mantiene una biblioteca Anti-CSRF para estos casos de esquina. Funciona con tokens de un solo uso por formulario, exclusivamente. Cuando se almacenan suficientes tokens en los datos de la sesión (configuración predeterminada: 65535), primero se ciclarán los tokens no canjeados más antiguos.