php - validate - ¿Nuevo token de CSRF por solicitud o NO?
html form without csrf protection (4)
En general, basta con tener un solo token por usuario o por sesión. Es importante que el token esté vinculado a un usuario / sesión en particular y no se use de forma global.
Si teme que el token pueda ser filtrado u obtenido por un sitio atacante (por ejemplo, por XSS), puede limitar la validez del token a un determinado período de tiempo, una determinada forma / URL o una cierta cantidad de usos.
Pero limitar la validez tiene el inconveniente de que podría dar como resultado falsos positivos y, por lo tanto, restricciones en la usabilidad, e. gramo. una solicitud legítima podría usar un token que simplemente se ha invalidado porque la solicitud del token es demasiado antigua o el token ya se ha utilizado con demasiada frecuencia.
Entonces mi recomendación es usar solo un token por usuario / sesión. Y si desea mayor seguridad, utilice un token por formulario / URL por usuario / sesión para que si se filtra un token de un formulario / URL, los otros sigan siendo seguros.
Así que estoy leyendo y estaba realmente confundido acerca de tener un token CSRF, ¿con qué debería generar un token nuevo por cada solicitud, o solo por hora o algo así?
$data[''token''] = md5(uniqid(rand(), true));
$_SESSION[''token''] = $data[''token''];
Pero digamos que es mejor generar un token cada hora, luego necesitaría dos sesiones: token, vencimiento,
¿Y cómo procederé con el formulario? Simplemente ponga echo $ _SESSION [''token''] en el formulario de valor oculto y luego compare en submit?
La respuesta a tu pregunta es: depende.
Y no necesita usar la sesión para tokens temporizados, solo puede usar la hora del servidor y una clave secreta en el servidor.
Pero digamos que es mejor generar un token cada hora, luego necesitaría dos sesiones: token, vencimiento,
No, necesitas una rutina que pueda generar un token para un marco de tiempo. Digamos que divides el tiempo cada 30 minutos. Usted crea un token para los 30 minutos actuales en el formulario.
Cuando se envía el formulario y se verifica el token en contra por ahora y en el período anterior de 30 minutos. Por lo tanto, un token es válido por 30 minutos hasta una hora.
$token = function($tick = 0) use($secret, $hash) {
$segment = ((int) ($_SERVER[''REQUEST_TIME''] / 1800)) + $tick;
return $hash($secret . $segment);
};
Puedes usar ambos métodos.
1) Un token aleatorio para cada solicitud. Y para resolver el problema de los tokens no sincronizados, puede usar los eventos enviados por el servidor http://www.w3.org/TR/eventsource/ o websockets http://www.w3.org/TR/websockets/ tecnología de comunicación para actualizar los tokens en tiempo real para cada página.
2) Puede usar un token por sesión de usuario (no es necesario hacerlo por hora) que es más fácil de implementar. No tendrá problemas con la sincronización, pero si el token no es demasiado fuerte, puede adivinarse. Ofcorse si el token es muy aleatorio, será muy difícil para una persona malentecida solicitar una falsificación.
El primer método de PS es el más seguro pero es más difícil de implementar y usa más recursos.
Si lo haces por solicitud de formulario, básicamente eliminas la posibilidad de que se produzcan ataques CSRF y puedes resolver otro problema común: envío de formularios múltiples
En términos simples: su aplicación solo aceptará la entrada de formulario si el usuario PREGUNTA el formulario antes de la presentación.
Escenario normal: el usuario A va a su sitio web, y le pide el formulario A, recibe el formulario A más un código único para el formulario A. Cuando el usuario envía el formulario A, debe incluir el código exclusivo para el formulario A.
Escenario de ataque de CSRF: el usuario A va a su sitio web y le pide el formulario A. Mientras tanto, visita otro sitio "malo", que intenta un ataque de CSRF contra ellos, y los somete a un formulario falso B.
Pero su sitio web sabe que el Usuario A nunca solicitó el Formulario B y, por lo tanto, aunque tengan el código único para el Formulario A, el Formulario B será rechazado porque no tienen un Código único del Formulario B, solo un código del Formulario A. Su usuario está seguro y puede dormir tranquilo por la noche.
Pero si lo hace como un token genérico, con una duración de una hora (como publicó anteriormente), entonces el ataque anterior podría funcionar, en cuyo caso no ha logrado mucho con su protección CSRF. Esto es porque la aplicación no sabe que la forma B nunca se solicitó en primer lugar. Es un token genérico. La prevención TODO EL PUNTO de CSRF es hacer que cada ficha sea única para esa forma
Editar: porque solicitó más información: 1 - no tiene que hacerlo por solicitud de formulario, puede hacerlo por hora / sesión, etc. El punto es un valor secreto que se le da al usuario y se vuelve a casar en la declaración. Este valor no es conocido por otro sitio web y, por lo tanto, no puede enviar un formulario falso.
Entonces, o bien generas el token por solicitud o por sesión:
// 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!!!
}
y debido a que es "por formulario", no recibirá envíos de formularios dobles, ¡porque puede borrar el token después del primer envío del formulario!