Ejemplo de ataque CSRF (falsificación de solicitudes entre sitios) y prevención en PHP

Tengo un sitio web donde la gente puede votar así:

http://mysite.com/vote/25 

Esto colocará una votación en el ítem 25. Quiero solo poner esto a disposición de los usuarios registrados, y solo si quieren hacer esto. Ahora sé cuando alguien está ocupado en el sitio web, y alguien les da un enlace como este:

 http://mysite.com/vote/30 

entonces la votación será para él sobre el tema sin que él quiera hacer esto.

He leído la explicación en el sitio web de OWASP , pero realmente no lo entiendo

Es este un ejemplo de CSRF, y cómo puedo prevenir esto. Lo mejor que puedo pensar es agregar algo al enlace como un hash. Pero esto será bastante irritante para poner algo al final de todos los enlaces. ¿No hay otra forma de hacer esto?

Otra cosa puede ser que alguien me dé otro ejemplo de esto, porque el sitio web me parece bastante fugaz.

Esto podría convertirse en un ejemplo de CSRF si:

  • ese enlace se obtiene (a través de una etiqueta , por ejemplo) : falsificación
  • desde otro sitio: sitio cruzado

Por ejemplo, si pudiera insertar esta etiqueta en el código fuente HTML de stackoverflow (y puedo, ya que stackoverflow le permite a uno usar tags en sus publicaciones) :

  

Simplemente hubieras votado por ese artículo 😉

La solución que generalmente se usa es colocar un token, que tiene un tiempo de vida limitado, en la URL y, cuando se recupera la URL, verifique que este token siga siendo válido.

La idea básica sería:

  • Al generar la página:
    • generar un token único
    • almacenarlo en la sesión del usuario
    • y colocarlo en los enlaces de la página, que se vería así: http://mysite.com/vote/30?token=AZERTYUHQNWGST
  • Cuando se llama la página de votación:
    • Verifica si el token está presente en la URL
    • Verifique si está presente en la sesión del usuario
    • Si no => no registra el voto

La idea allí es:

  • Los tokens no tienen una larga vida útil, y son difíciles de adivinar
  • Lo que significa que tu atacante :
    • tiene solo una ventana de unos minutos durante los cuales su inyección será válida
    • tendrá que ser bueno para adivinar ^^
    • tendrá que generar una página diferente para cada usuario.

Además, tenga en cuenta que cuanto más corta permanezca activa la sesión del usuario después de que abandone su sitio, menos riesgos hay de que siga siendo válido cuando visita el sitio web incorrecto.

Pero aquí, debes elegir entre seguridad y fácil de usar …

Otra idea (que no es totalmente segura, pero ayuda a los chicos que no saben cómo forzar una solicitud POST) , sería aceptar solo solicitudes POST cuando la gente está votando:

  • El navegador está enviando solicitudes GET para tags inyectadas
  • Como esta URL está modificando algunos datos, de todos modos, no debería funcionar con GET, sino solo con POST

Pero tenga en cuenta que esto no es perfectamente seguro: es (¿es probable?) Posible forzar / forjar una solicitud POST, con algo de Javascript.

Primero, la solicitud GET no debe usarse para alterar estados en el servidor, por lo que para su servicio de votación recomendaría POST / PUT. Esto es solo una guía, pero una cuchilla.

Entonces, para su pregunta, CSRF es un problema del cliente por lo que no importa qué tipo de lenguaje de servidor use (PHP en su caso). La solución estándar es la misma y es así: tener un valor aleatorio en los datos URI / POST y el mismo valor en el encabezado Cookie. Si esas coincidencias, puede estar seguro de que no hay CSRF. Hay mucha información acerca de cómo esto se puede hacer aquí en StackOverflow, por ejemplo. este .
¡Buena suerte!

OWASP tiene un CSRFGuard para PHP y ESAPI para PHP que escribí hace mucho tiempo para XMB -> UltimaBB -> GaiaBB.

http://code.google.com/p/gaiabb-olpc/source/search?q=function+get_new_token&origq=function+get_new_token&btnG=Search+Trunk

Parece que algunos otros han limpiado ese código y permitido tokens más fuertes:

https://www.owasp.org/index.php/PHP_CSRF_Guard

gracias, Andrew