ruby on rails - Rails 4 omitiendo protect_from_forgery para acciones de API
ruby-on-rails json (2)
He estado implementando una aplicación de Rails 4 con una API. Quiero ser capaz de llamar a la API desde teléfonos móviles y la aplicación web en sí. Encontré esta nota mientras investigaba protect_from_forgery
:
Es importante recordar que las solicitudes XML o JSON también se ven afectadas y, si estás creando una API, necesitarás algo como:
class ApplicationController < ActionController::Base
protect_from_forgery
skip_before_action :verify_authenticity_token, if: :json_request?
protected
def json_request?
request.format.json?
end
end
Estaba pensando en hacer esto, pero tengo algunas reservas / preguntas:
- Esta solución parece dejar el agujero CSRF abierto porque ahora un atacante podría crear un enlace con un
onclick
javascript que publique JSON. - ¿Sería un sustituto razonable buscar un token de API? es decir, ¿qué
handle_unverified_request
si en lugar de omitir la comprobación de autenticidad, permitiéndole suspender el control y recuperar enhandle_unverified_request
si el token api está presente y es correcto para el usuario actual? - ¿O tal vez debería simplemente hacer que la aplicación web y los dispositivos móviles envíen el token CSRF en los encabezados HTTP ? ¿Eso es seguro? ¿Cómo podría el teléfono móvil incluso obtener el token CSRF, dado que, para empezar, no está procesando formularios HTML?
Editar para aclarar:
Me preocupa más que el usuario de webapp haga clic en un enlace CSRF creado. Los usuarios móviles están autenticados, autorizados y tienen una clave API, por lo que no estoy preocupado por ellos. Pero al habilitar la protección CSRF para los usuarios de aplicaciones web, los usuarios de dispositivos móviles no pueden usar la API protegida. Quiero saber la estrategia correcta para manejar esto, y no creo que la documentación de Rails dé la respuesta correcta.
Enviar el token CSRF en un encabezado HTTP es de hecho un enfoque común. Asegura que el cliente haya obtenido de alguna forma un token válido. Por ejemplo, se enviará un enlace CSRF elaborado con cookies de credenciales, pero el encabezado no incluirá el token CSRF. Su propia javascript en el cliente tendrá acceso a las cookies de dominio y podrá copiar el token de una cookie al encabezado en todas las solicitudes de XHR.
AngularJS sigue este enfoque, como se explica aquí .
En cuanto a sus primeras dos preguntas:
- Esta solución parece dejar el agujero CSRF abierto ...
De hecho, esta es la razón por la que no debe deshabilitar el token CSRF también en su API.
- ¿Sería un sustituto razonable buscar un token de API? ...
Probablemente no. Tenga en cuenta lo siguiente (de OWASP ):
Los tokens CSRF en solicitudes GET pueden filtrarse en varias ubicaciones: historial del navegador, archivos de registro HTTP, dispositivos de red que hacen un punto para registrar la primera línea de una solicitud HTTP y encabezados Referer si el sitio protegido se vincula a un sitio externo.
Recomendación general : no intente inventar la rueda. OWASP tiene una página llamada REST Security Cheat Sheet , así como la que he vinculado anteriormente. Puede seguir el enfoque angular (copiar el token de una cookie a un encabezado en cada solicitud XHR) y para los formularios normales que no son Ajax, asegúrese de usar solo POST y un campo oculto como normalmente se hace en la protección CSRF de formularios de servidor estáticos .
Un atacante podría CURL en sus controladores todo lo que quiera, pero si su API requiere autenticación, no llegará a ninguna parte.
Hacer que los consumidores API envíen un CSRF no es realmente lo que CSRF hace. Para hacer esto, necesitaría implementar un tipo de mecanismo de golpeteo donde su cliente llegue a un punto final de autorización primero para obtener el código (también conocido como CSRF) y luego enviarlo en el POST. esto es una mierda para los clientes móviles porque usa su ancho de banda, potencia y es lento.
Y de todos modos, ¿es realmente una falsificación (es decir, la F en CSRF) si es un cliente autorizado que golpea su controlador después de todo?