¿Qué es un token CSRF? ¿Cuál es su importancia y cómo funciona?


629

Estoy escribiendo una aplicación (Django, sucede) y solo quiero tener una idea de qué es realmente un "token CSRF" y cómo protege los datos. ¿Los datos de publicación no son seguros si no usa tokens CSRF?


13
Es un token secreto específico del usuario en todas las presentaciones de formularios y URL de efectos secundarios para evitar falsificaciones de solicitudes entre sitios. Más información aquí: en.wikipedia.org/wiki/Cross-site_request_forgery
Robert Harvey

1
parece que hay una delgada línea entre proteger una pregunta y prohibirla por ser demasiado amplia: D
anton1980

2
De la hoja de trucos de prevención de falsificación de solicitudes entre sitios (CSRF) de OWASP : " La creación de secuencias de comandos entre sitios no es necesaria para que CSRF funcione. Sin embargo, cualquier vulnerabilidad de secuencias de comandos entre sitios se puede utilizar para vencer todas las técnicas de mitigación de CSRF [...]. Esto se debe a que una carga útil XSS simplemente puede leer cualquier página del sitio utilizando una solicitud XMLHttpRequest. [...] Es imperativo que no existan vulnerabilidades XSS para garantizar que las defensas CSRF no puedan ser eludidas. "
toraritte

Respuestas:


1497

Falsificación de solicitudes entre sitios (CSRF) en palabras simples

  • Suponga que actualmente está conectado a su banca en línea en www.mybank.com
  • Suponga que una transferencia de dinero mybank.comdará como resultado una solicitud (conceptual) del formulario http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>. (Su número de cuenta no es necesario porque está implícito en su inicio de sesión).
  • Usted visita www.cute-cat-pictures.org, sin saber que es un sitio malicioso.
  • Si el propietario de ese sitio conoce la forma de la solicitud anterior (¡fácil!) Y adivina correctamente que ha iniciado sesión mybank.com(¡requiere suerte!), Podría incluir en su página una solicitud como http://www.mybank.com/transfer?to=123456;amount=10000(¿dónde 123456está el número de su cuenta en las Islas Caimán? y 10000es una cantidad que antes creías que te alegraba poseer).
  • Usted recuperado que www.cute-cat-pictures.orgla página, por lo que su navegador hará que esa solicitud.
  • Su banco no puede reconocer este origen de la solicitud: su navegador web enviará la solicitud junto con su www.mybank.comcookie y se verá perfectamente legítima. Ahí va tu dinero!

Este es el mundo sin tokens CSRF .

Ahora para el mejor con tokens CSRF :

  • La solicitud de transferencia se extiende con un tercer argumento: http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971.
  • Ese token es un número aleatorio enorme e imposible de adivinar que mybank.comse incluirá en su propia página web cuando se lo sirvan. Es diferente cada vez que sirven cualquier página a alguien.
  • El atacante no puede adivinar el token, no puede convencer a su navegador web para que lo entregue (si el navegador funciona correctamente ...), por lo que el atacante no podrá crear una solicitud válida, porque las solicitudes con el la ficha incorrecta (o ninguna ficha) será rechazada por www.mybank.com.

Resultado: Mantiene sus 10000unidades monetarias. Le sugiero que done algo de eso a Wikipedia.

(Su experiencia puede ser diferente.)

EDITAR del comentario que vale la pena leer:

Sería digno de notar que el script de www.cute-cat-pictures.orgnormalmente no tiene acceso a su token anti-CSRF www.mybank.comdebido al control de acceso HTTP. Esta nota es importante para algunas personas que envían un encabezado Access-Control-Allow-Origin: *sin razón para cada respuesta del sitio web sin saber para qué sirve, simplemente porque no pueden usar la API desde otro sitio web.


36
Y, obviamente, el token se llamaría idealmente token anti- CSRF, pero el nombre probablemente sea lo suficientemente complicado como es.
Lutz Prechelt

3
@LutzPrechelt gracias. ¿Por qué JavaScript no puede obtener ningún token de autenticidad del navegador?
BKSpurgeon

72
Sería digno de notar que el script de www.cute-cat-pictures.orgnormalmente no tiene acceso a su token anti-CSRF www.mybank.comdebido al control de acceso HTTP. Esta nota es importante para algunas personas que envían un encabezado Access-Control-Allow-Origin: *sin razón para cada respuesta del sitio web sin saber para qué sirve, simplemente porque no pueden usar la API desde otro sitio web.
SOFe

99
@AugustinRiedinger Si el atacante abre la página web en su computadora, ya que no tiene la cookie del usuario conectado, no recibirá el token csrf correspondiente (cada token csrf debe ser válido solo para una sesión de usuario específica). Si el atacante intenta cargar la página web que contiene el token en la computadora del usuario, con un script colocado en el sitio web cute-cat-pictures, el navegador le impedirá leer el www.mybank.com (y el token) debido a misma política de origen
Marcel

13
@LutzPrechelt Creo que no es suficiente que el token sea siempre diferente, debe emparejarse con una sesión y el servidor debe verificar que el token que recibe se generó para una sesión que el servidor identifica mediante la cookie recibida. De lo contrario, el hacker puede visitar mybank y obtener un token válido. Entonces, si usa un nuevo token con cada formulario, debe guardarlo junto con el ID de sesión en el servidor. Probablemente sea más fácil usar el mismo token por sesión.
Marcel

222

Sí, los datos de publicación son seguros. Pero el origen de esos datos no lo es. De esta manera, alguien puede engañar al usuario con JS para que inicie sesión en su sitio, mientras navega por la página web del atacante.

Para evitar eso, django enviará una clave aleatoria tanto en la cookie como en los datos del formulario. Luego, cuando los usuarios POST, verificará si dos claves son idénticas. En caso de que el usuario sea engañado, el sitio web de terceros no puede obtener las cookies de su sitio, lo que provoca un error de autenticación.


@DmitryShevchenko Hola, tratando de entender cómo es este método de cookie + formulario de entrada diferente de simplemente validar el referente en el lado del servidor. Todos los ejemplos que encuentro están relacionados con un pirata informático que engaña al usuario para publicar desde su sitio en el sitio real.
Ethan

Ok, descubrí por qué no se usa el referente. Está bloqueado en muchos casos ya que a veces se considera que contiene información confidencial. Las empresas y sus representantes suelen hacer eso. Sin embargo, si se usa HTTPS, es más probable que no se bloquee.
Ethan

44
Es fácil cambiar de referencia, no diría que es una información confiable. El token CSRF, sin embargo, se genera utilizando la clave secreta del servidor y generalmente está vinculado al usuario
Dmitry Shevchenko el

1
Realmente no entiendo por qué esto es una amenaza para la seguridad. El usuario iniciará sesión en otro sitio ... pero el sitio original no tendrá ninguna forma de recuperar esa información. ¿Derecha?
Aakil Fernandes

66
Bueno, supongamos que inyecto un iframe malicioso de " bank.com/transfer?from=x&to=y " en, por ejemplo, Facebook.com. Si es cliente de bank.com y va a Facebook, ese iframe cargará la página del banco con sus cookies (porque el navegador las enviará a un dominio conocido) y realizará una transferencia de dinero. Sin que sepas nada.
Dmitry Shevchenko

74

El sitio genera un token único cuando hace la página del formulario. Este token es necesario para publicar / recuperar datos en el servidor.

Dado que su sitio genera el token y se proporciona solo cuando se genera la página con el formulario, algún otro sitio no puede imitar sus formularios; no tendrán el token y, por lo tanto, no podrán publicar en su sitio.


10
¿Podría un usuario tomar la salida del token dentro de la fuente, tomar la cookie que se le envió y luego enviarla desde un sitio de terceros?
Jack Marchetti

99
@JackMarchetti sí. pero sería costoso ya que cada vez que quisiera enviar el formulario desde un sitio de terceros tendría que cargar la página y analizar el token. Los tokens CSRF deberían combinarse idealmente con otras formas de seguridad si le preocupa este vector de ataque
tkone

44
Tengo la misma pregunta que @JackMarchetti, lo que no está claro es si el token CSRF cambia en cada inicio de sesión. Si se mantiene igual, ¿qué evitaría que un atacante primero inicie sesión, tome el token de solicitud y luego inserte ese token en el ataque?
Paul Preibisch 05 de

77
@PaulPreibisch debería cambiar en cada carga de la página, no en cada inicio de sesión. De esta forma, el atacante tendría que solicitar la página cada vez que quisiera enviar el formulario. Lo hace mucho más difícil.
tkone

99
@tkone, en realidad no lo hace mucho más difícil. Si solo duplica la cantidad de esfuerzo y tiempo. No agrega ningún tipo de procesamiento prohibitivo. El truco también es asociar el token CSRF a una cookie específica de dominio y enviar esta cookie junto con el formulario. Tanto la cookie como los datos de publicación del formulario tendrían que enviarse al servidor en la solicitud POST. De esta forma, se requeriría un ataque de secuestro de cookies para poder emular una solicitud legítima.
Pedro Cordeiro

56

El blog Cloud Under tiene una buena explicación de los tokens CSRF.

Imagine que tiene un sitio web como un Twitter simplificado, alojado en a.com. Los usuarios registrados pueden ingresar texto (un tweet) en un formulario que se envía al servidor como una solicitud POST y se publica cuando presionan el botón Enviar. En el servidor, el usuario se identifica mediante una cookie que contiene su ID de sesión única, por lo que su servidor sabe quién publicó el Tweet.

La forma podría ser tan simple como eso:

 <form action="http://a.com/tweet" method="POST">
   <input type="text" name="tweet">
   <input type="submit">
 </form> 

Ahora imagine que un chico malo copia y pega este formulario en su sitio web malicioso, digamos b.com. La forma aún funcionaría. Siempre que un usuario haya iniciado sesión en su Twitter (es decir, que tenga una cookie de sesión válida para a.com), la solicitud POST se enviará http://a.com/tweety procesará como de costumbre cuando el usuario haga clic en el botón Enviar.

Hasta ahora, este no es un gran problema, siempre y cuando el usuario esté al tanto de lo que hace exactamente el formulario, pero qué pasa si nuestro chico malo modifica el formulario de esta manera:

 <form action="https://example.com/tweet" method="POST">
   <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad">
   <input type="submit" value="Click to win!">
 </form> 

Ahora, si uno de tus usuarios termina en el sitio web del malo y presiona el botón "¡Haz clic para ganar!" botón, el formulario se envía a su sitio web, el usuario se identifica correctamente mediante la ID de sesión en la cookie y se publica el Tweet oculto.

Si nuestro chico malo fuera aún peor, haría que el usuario inocente envíe este formulario tan pronto como abra su página web usando JavaScript, tal vez incluso completamente oculto en un iframe invisible. Esto es básicamente una falsificación de solicitud entre sitios.

Un formulario se puede enviar fácilmente desde cualquier lugar a todas partes. En general, esa es una característica común, pero hay muchos más casos en los que es importante permitir que solo se envíe un formulario desde el dominio al que pertenece.

Las cosas son aún peores si su aplicación web no distingue entre solicitudes POST y GET (por ejemplo, en PHP usando $ _REQUEST en lugar de $ _POST). ¡No hagas eso! Las solicitudes de modificación de datos se pueden enviar tan fácilmente como<img src="http://a.com/tweet?tweet=This+is+really+bad"> integrarse en un sitio web malicioso o incluso en un correo electrónico.

¿Cómo me aseguro de que un formulario solo se pueda enviar desde mi propio sitio web? Aquí es donde entra en juego el token CSRF. Un token CSRF es una cadena aleatoria, difícil de adivinar. En una página con un formulario que desea proteger, el servidor generará una cadena aleatoria, el token CSRF, lo agregará al formulario como un campo oculto y también lo recordará de alguna manera, ya sea almacenándolo en la sesión o configurando una cookie que contiene el valor Ahora el formulario se vería así:

    <form action="https://example.com/tweet" method="POST">
      <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn">
      <input type="text" name="tweet">
      <input type="submit">
    </form> 

Cuando el usuario envía el formulario, el servidor simplemente tiene que comparar el valor del campo csrf-token publicado (el nombre no importa) con el token CSRF recordado por el servidor. Si ambas cadenas son iguales, el servidor puede continuar procesando el formulario. De lo contrario, el servidor debería detener inmediatamente el procesamiento del formulario y responder con un error.

¿Por qué funciona esto? Hay varias razones por las cuales el malo de nuestro ejemplo anterior no puede obtener el token CSRF:

Copiar el código fuente estático de nuestra página a un sitio web diferente sería inútil, porque el valor del campo oculto cambia con cada usuario. Sin que el sitio web del malo conozca el token CSRF del usuario actual, su servidor siempre rechazará la solicitud POST.

Debido a que la página maliciosa del malo es cargada por el navegador de su usuario desde un dominio diferente (b.com en lugar de a.com), el malo no tiene la posibilidad de codificar un JavaScript, que carga el contenido y, por lo tanto, el token CSRF actual de nuestro usuario su página web. Esto se debe a que los navegadores web no permiten solicitudes AJAX entre dominios de forma predeterminada.

El malo tampoco puede acceder a la cookie establecida por su servidor, porque los dominios no coincidirían.

¿Cuándo debo proteger contra la falsificación de solicitudes entre sitios? Si puede asegurarse de no mezclar GET, POST y otros métodos de solicitud como se describe anteriormente, un buen comienzo sería proteger todas las solicitudes POST de forma predeterminada.

No tiene que proteger las solicitudes PUT y DELETE, porque como se explicó anteriormente, un navegador no puede enviar un formulario HTML estándar utilizando esos métodos.

JavaScript, por otro lado, puede hacer otros tipos de solicitudes, por ejemplo, utilizando la función $ .ajax () de jQuery, pero recuerde, para que las solicitudes AJAX funcionen, los dominios deben coincidir (siempre y cuando no configure explícitamente su servidor web) .

Esto significa que, a menudo, ni siquiera tiene que agregar un token CSRF a las solicitudes AJAX, incluso si son solicitudes POST, pero tendrá que asegurarse de que solo omita la verificación CSRF en su aplicación web si la solicitud POST es realmente un Solicitud AJAX. Puede hacerlo buscando la presencia de un encabezado como X-Requested-With, que las solicitudes de AJAX generalmente incluyen. También puede establecer otro encabezado personalizado y verificar su presencia en el lado del servidor. Eso es seguro, ya que un navegador no agregaría encabezados personalizados a un envío de formulario HTML normal (ver arriba), por lo que no es posible que el Sr. Bad Guy simule este comportamiento con un formulario.

Si tiene dudas acerca de las solicitudes AJAX, porque por alguna razón no puede verificar un encabezado como X-Requested-With, simplemente pase el token CSRF generado a su JavaScript y agregue el token a la solicitud AJAX. Hay varias maneras de hacer esto; ya sea agregarlo a la carga útil como lo haría un formulario HTML normal, o agregar un encabezado personalizado a la solicitud AJAX. Siempre que su servidor sepa dónde buscarlo en una solicitud entrante y pueda compararlo con el valor original que recuerda de la sesión o cookie, estará ordenado.


Gracias por la informacion detallada. Durante la solicitud posterior, el sitio debe enviar el token csrf al servidor, entonces, ¿cuándo enviará el cliente este token csrf al servidor? ¿Es mientras se realiza la solicitud de opciones de verificación previa? Elabore esta parte ..
Sm Srikanth

@ Dan ¿Cómo es que b.com puede acceder a las cookies de otro sitio a.com?
zakir

8

La raíz de todo es asegurarse de que las solicitudes provienen de los usuarios reales del sitio. Se genera un token csrf para los formularios y debe estar vinculado a las sesiones del usuario. Se utiliza para enviar solicitudes al servidor, en el que el token las valida. Esta es una forma de protección contra csrf, otra sería verificar el encabezado de referencia.


77
No confíe en el encabezado del árbitro, puede falsificarse fácilmente.
kag

3
¡Esta es la respuesta correcta! El token DEBE estar vinculado a una sesión en el servidor. Comparar los datos de Cookie + Form como la respuesta más votada sugiere que es completamente incorrecto. Estos componentes forman parte de la solicitud, que el cliente construye.
Lee Davis

3
En realidad no. El token DEBE estar vinculado a cada SOLICITUD al servidor. Si solo lo vincula a la sesión, corre el riesgo de que alguien robe el token de la sesión y envíe una solicitud con ese token. Entonces, para máxima seguridad, el token debe estar vinculado a cada solicitud http.
chrisl08
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.