El ataque de Cross Site Request Forgery
(CSRF) consiste en engañar al usuario para que pinche en un enlace que provoca alguna acción en nuestro sitio (de ahí la idea de ataque cruzado). Es un fallo que se puede aprovechar cuando nuestra aplicación web no verifica que las peticiones vienen de donde deben.
The basic idea behind a CSRF attack is this; you have a user that uses their browser to login to your website (let’s say “awesomebank.com” as an example). Now that same user uses the same browser to visit a malicious website, and that malicious website sends a request to your website. In certain cases, the browser will send cookies for your website along with that request, even though it came from the malicious website. From your server’s perspective, you get an API call from an authenticated user, so you’ll probably end up doing what the malicious site wants you to do.
En Avoiding CSRF Attacks with API Design se refieren a un caso particular y es el de las APIs.
Los sitios web van teniendo protecciones y los navegadores también ayudan pero, aún así, hay algunas precauciones que podemos tomar.
La primera, no utilizar GET
para modificar estados. Esto es, en general, una mmala idea, pero desde el punto de vista de seguridad puede ser muy grave. Bastaría que alguien cargue una imagen con el enlace (o intente cargar) y se ejecutaría la acción.
Fortunately, it’s easy to avoid this; just don’t let GET requests modify state.
Utilizar `tokens’ anti-CSRF.
Cuando le enviamos un formulario a alguien generamos un identificador y lo guardamos con la sesión. Cuando nos responden, lo que venga tiene que llevar el identificador y nosotros verificamos que coincide con el generado antes de ejecutar la acción.
One way to secure yourself here is to use something called a CSRF token. The basic idea is to generate a random token and store it in your user session, then make it so the CSRF token is either submitted by forms in a hidden field or added as an extra “x-csrf-token” header in each API call. Server side, you can check to make sure the CSRF token matches the one stored in the session. Since it should be impossible for an attacker to get the CSRF token (the same origin policy does protect javascript from reading the contents of a response) it makes it much more difficult for an attacker.
Un problema de estos tokens es cuando la interacción no se realiza con un navegador, y habrá que contemplar este caso si es necesario. O, si confiamos en este tipo de interacciones (al fin y al cabo, ya no es tan sencillo que un usuario reciba estas peticiones) incluir las excepciones adecuadas (pero mejor tenerlo en cuenta y no bajar la guardia).
There are a few ways around this. First, note that really only POST requests with a content-type of “application/x-www-form-urlencoded”, “multipart/form-data”, or “text/plain” need a CSRF token, because of the same origin policy. So you could not require a CSRF token for posts with a content-type of “application/json” (although some would caution against relying on content-type as your only layer of protection against CSRF). Also, if you are using this strategy, pay special attention to endpoints which do not require a body.
Comprobar la cabecera de origen. ¿Desde dónde nos puede llegar una petición?
To protect against this; if you do need to allow cross-domain requests, instead of allowing access to “*”, pick a whitelist of origins that are allowed to access your API and only allow those in.
Escribir casos de prueba negativos. Esto es, incluir en nuestras pruebas intentos maliciosos y verificar que generan los errores adecuados.
Write some test cases that try sending an OPTIONS request to your API with an `origin: evilcorp.com” header, and make sure you get back an error, or at least don’t get back an “Access-Control-Allow-Origin” header. Try sending data encoded as “application/x-www-form-urlencoded” to an endpoint that is expecting “application/json” (or to an endpoint that doesn’t expect a body) and make sure this fails.
Utilizar la política de cookies
del mismo sitio. Esto es, si la petición viene del sitio incorrecto, ¿para qué le vamos a enviar las cookies?
One thing you might be wondering - when evilcorp.com sends a request to awesomebank.com, why are the awesomebank.com cookies being sent at all? Doesn’t this seem very insecure by design? Well, there’s a relatively new standard called “SameSite” cookies which will stop those cookies from being sent.
Finalmente, cuando vayamos a realizar operaciones destructivas o delicadas podemos solicitar una nueva autentificación. Si la contraseña es necesaria, el enlace con el ataque CSRF no funcionará.
If you have an especially destructive operation, such as deleting an account or sending all of your money to the Cayman Islands, consider requiring your user to re-authenticate. If the password is a required field in the request, then a CSRF attack can’t succeed, since the attacking website has no way of knowing the user’s password.