ruby on rails - elaborando - Rails diseño de API sin deshabilitar la protección CSRF
ruby on rails api rest (2)
Rails funciona con la convención ''secure by default''. La falsificación de solicitudes entre sitios o entre sesiones requiere que el usuario tenga un navegador y otro sitio web confiable. Esto no es relevante para las API, ya que no se ejecutan en el navegador y no mantienen ninguna sesión. Por lo tanto, debe desactivar CSRF para API.
Por supuesto, debe proteger su API al requerir Autenticación HTTP o un token API implementado personalizado o una solución OAuth.
En febrero de 2011, Rails se modificó para requerir el token CSRF para todas las solicitudes no GET , incluso aquellas para un punto final API. Entiendo la explicación de por qué este es un cambio importante para las solicitudes del navegador, pero esa publicación de blog no ofrece ningún consejo sobre cómo una API debe manejar el cambio.
No estoy interesado en deshabilitar la protección CSRF para ciertas acciones.
¿Cómo se supone que las API lidian con este cambio? ¿La expectativa de que un cliente API haga una solicitud GET a la API para obtener un token CSRF, luego incluye ese token en cada solicitud durante esa sesión?
Parece que el token no cambia de un POST a otro. ¿Es seguro asumir que el token no cambiará durante la sesión?
No me gusta el manejo de error adicional cuando expira la sesión, pero supongo que es mejor que tener que OBTENER un token antes de cada solicitud POST / PUT / DELETE.
Una vieja pregunta, pero la seguridad es lo suficientemente importante como para sentir que merece una respuesta completa. Como se discutió en esta question , aún existe cierto riesgo de CSRF incluso con API. Sí, se supone que los navegadores evitan esto por defecto, pero como no tiene el control completo del navegador y de los complementos que el usuario ha instalado, se debe considerar como una mejor práctica para protegerse contra CSRF en su API.
La forma en que lo he visto a veces es analizar la metaetiqueta CSRF desde la propia página HTML. Realmente no me gusta esto, ya que no encaja bien con la forma en que funcionan muchas aplicaciones de una sola página + API hoy en día y creo que el token CSRF debe enviarse en cada solicitud, independientemente de si es HTML, JSON o XML.
Así que sugeriría en su lugar pasar un token CSRF como un valor de cookie o encabezado a través de un filtro posterior para todas las solicitudes. La API simplemente puede volver a enviar esa devolución como un valor de encabezado de X-CSRF-Token
que Rails ya verifica.
Así es como lo hice con AngularJS:
# In my ApplicationController
after_filter :set_csrf_cookie
def set_csrf_cookie
if protect_against_forgery?
cookies[''XSRF-TOKEN''] = form_authenticity_token
end
end
AngularJS busca automáticamente una cookie llamada XSRF-TOKEN
pero no dude en XSRF-TOKEN
nombre que desee para sus propósitos. Luego, cuando envíe un mensaje POST / PUT / DELETE, debe establecer la propiedad de encabezado X-CSRF-Token
que Rails busca automáticamente.
Desafortunadamente, AngualrJS ya envía de vuelta la cookie XSRF-TOKEN
en un valor de encabezado de X-XSRF-TOKEN
. Es fácil anular el comportamiento predeterminado de Rails para acomodar esto en ApplicationController
esta manera:
protected
def verified_request?
super || form_authenticity_token == request.headers[''X-XSRF-TOKEN'']
end
Para Rails 4.2 ahora hay un asistente integrado para validar el CSRF que se debe usar.
protected
def verified_request?
super || valid_authenticity_token?(session, request.headers[''X-XSRF-TOKEN''])
end
Espero que sea útil.
EDITAR: En una discusión sobre esto para una solicitud de extracción de Rails que presenté salió que pasar el token de CSRF a través de la API para iniciar sesión es una práctica particularmente mala (por ejemplo, alguien podría crear un inicio de sesión de terceros para su sitio que usa credenciales de usuario en lugar de tokens). Así que cavet emptor. Depende de usted decidir qué tan preocupado está sobre eso para su aplicación. En este caso, podría seguir utilizando el enfoque anterior, pero solo devolverá la cookie CSRF a un navegador que ya tenga una sesión autenticada y no para cada solicitud. Esto evitará enviar un inicio de sesión válido sin usar la metaetiqueta CSRF.