¿Cómo protejo las llamadas a la API REST?

91

Estoy desarrollando la aplicación web restful que usa un marco web popular en el backend, digamos (rails, sinatra, flask, express.js). Idealmente, quiero desarrollar el lado del cliente con Backbone.js. ¿Cómo dejo que solo mi lado del cliente javascript interactúe con esas llamadas a la API? No quiero que esas llamadas a la API sean públicas y las llame curlo simplemente ingrese el enlace en el navegador.

knd
fuente
¿Todas sus llamadas a la API requieren un token que se pasa al cliente cuando se publica su página?
Hajpoj
El SDK de JavaScript de Amazon AWS utiliza una URL de objeto firmada previamente: - docs.aws.amazon.com/AmazonS3/latest/dev/…
rjha94

Respuestas:

90

Como primer principio, si su cliente JS consume su API, debe asumir que es pública: un depurador JS simple pone a un atacante en una posición en la que puede enviar una solicitud idéntica byte por byte desde un herramienta de su elección.

Dicho esto, si leí tu pregunta correctamente, esto no es lo que quieres evitar: lo que realmente no quieres que suceda es que tu API se consuma (de forma regular) sin que tu cliente JS esté involucrado. Aquí hay algunas ideas sobre cómo, si no hacer cumplir, al menos fomentar el uso de su cliente:

  • Estoy seguro de que su API tiene algún tipo de campo de autenticación (por ejemplo, Hash calculado en el cliente). Si no, eche un vistazo a esta pregunta SO . Asegúrese de usar una sal (o incluso una clave API) que se le da a su cliente JS por sesión (no codificada). De esta manera, un consumidor no autorizado de su API se ve obligado a trabajar mucho más.

  • Al cargar el cliente JS, recuerde algunos encabezados HTTP (me viene a la mente el agente de usuario) y la dirección IP y solicite una nueva autenticación si cambian, empleando listas negras para los sospechosos habituales. Esto obliga al atacante a volver a hacer su tarea más a fondo.

  • En el lado del servidor, recuerde las últimas llamadas a la API y, antes de permitir otra, verifique si la lógica empresarial permite la nueva en este momento: esto le niega a un atacante la capacidad de concentrar muchas de sus sesiones en una sesión con su servidor: En En combinación con las otras medidas, esto hará que un abusador sea fácilmente detectable.

Puede que no haya dicho eso con la claridad necesaria: considero imposible hacer que sea completamente imposible que un abusador consuma su servicio, pero puede hacerlo tan difícil que tal vez no valga la pena.

Eugen Rieck
fuente
esta es información útil, pero ¿qué pasa si quiero hacer algo de autenticación desde mi api de backend a otra aplicación de api como un servidor separado? Para simplificar mi pregunta, quiero que mi back-end también conocido como node.js envíe una solicitud de recuperación a otro back- servidor final que es el mío, por algunas razones es necesario, pero quiero proteger las llamadas de la API, ya que puede acceder a datos confidenciales y no puedo usar sesions o jwt porque no puedo almacenarlos en el navegador.
La pirámide
@Thepyramid No importa lo que haga la llamada a la API en el lado del servidor, especialmente si el lado del servidor hace otra llamada a la API de segundo nivel. La parte importante es tratar su servidor no como un proxy, sino como una aplicación.
Eugen Rieck
¿Puede explicar más cómo hacer una aplicación, no un proxy?
La pirámide
1
Lo que quiero decir es: para obtener una cantidad decente de seguridad, debe emplear todas las herramientas que tiene una aplicación web: sesiones, una base de datos de autenticación, una lógica de negocios. Si no hace eso y simplemente trata su servidor como una forma de pasar solicitudes a otro servidor, simplemente lo está usando como un proxy para ese otro servidor y está limitado por la seguridad que ofrece el otro servidor.
Eugen Rieck
1
@PirateApp Un atacante puede ignorar fácilmente los encabezados CSRF. Solo funcionan si el dispositivo final es un navegador sin parches
Eugen Rieck
12

Debería implementar algún tipo de sistema de autenticación. Una buena forma de manejar esto es definir algunas variables de encabezado esperadas. Por ejemplo, puede tener una llamada API de autenticación / inicio de sesión que devuelva un token de sesión. Las llamadas posteriores a su API esperarán que se establezca un token de sesión en una variable de encabezado HTTP con un nombre específico como 'your-api-token'.

Alternativamente, muchos sistemas crean tokens de acceso o claves que se esperan (como youtube, facebook o twitter) usando algún tipo de sistema de cuentas api. En esos casos, su cliente tendría que almacenarlos de alguna manera en el cliente.

Entonces es simplemente una cuestión de agregar una verificación para la sesión en su marco REST y lanzar una excepción. Si es posible, el código de estado (estar tranquilo) sería un error 401.

gview
fuente
8
Aunque no hay nada que les impida mirar los encabezados y reproducirlos.
cdmckay
1
@cdmckay: un token debe coincidir con un token almacenado en una sesión. Simplemente reproducir el encabezado resultará en una respuesta "No autorizado" si proviene de una sesión diferente.
Andrei Volgin
3
Sin embargo, aún pueden usar la misma sesión y alterar las solicitudes antes de que se envíen a la API ... o incluso usar la consola en tiempo de ejecución para generar una llamada con encabezados / campos coincidentes modificando solo las partes que necesita ...
Potter Rafed
2
@PotterRafed: Si un usuario accede a su propia sesión válida, eso se llama usar una aplicación, no atacarla. El propósito de la autenticación es evitar el acceso a las sesiones / datos de otros usuarios .
Andrei Volgin
@AndreiVolgin sí, es justo, pero sigue siendo una vulnerabilidad
Potter Rafed
9

Ahora hay un estándar abierto llamado "JSON Web Token",

ver https://jwt.io/ y https://en.wikipedia.org/wiki/JSON_Web_Token

JSON Web Token (JWT) es un estándar abierto basado en JSON (RFC 7519) para crear tokens que afirman cierto número de afirmaciones. Por ejemplo, un servidor podría generar un token que tenga el reclamo "iniciado sesión como administrador" y proporcionárselo a un cliente. El cliente podría usar ese token para demostrar que inició sesión como administrador. Los tokens están firmados por la clave del servidor, por lo que el servidor puede verificar que el token es legítimo. Los tokens están diseñados para ser compactos, seguros para URL y utilizables, especialmente en el contexto de inicio de sesión único (SSO) del navegador web. Las afirmaciones de JWT se pueden utilizar normalmente para pasar la identidad de los usuarios autenticados entre un proveedor de identidad y un proveedor de servicios, o cualquier otro tipo de reclamaciones según lo requieran los procesos comerciales. [1] [2] Los tokens también se pueden autenticar y cifrar. [3] [4]

bbozo
fuente
¿Qué evitaría que un usuario copie su token y lo use en cualquier otra respuesta?
Ulad Kasach
1
@UladKasach para ser honesto, nunca profundicé en ellos, pero afaik son caducables, únicos para su usuario y encriptados por SSL (que por supuesto está practicando), es exactamente la misma idea detrás de oauth afaik
bbozo
3

Disculpe @MarkAmery y Eugene, pero eso es incorrecto.

Su aplicación js + html (cliente) que se ejecuta en el navegador PUEDE configurarse para excluir llamadas directas no autorizadas a la API de la siguiente manera:

  1. Primer paso: configurar la API para que requiera autenticación. El cliente primero debe autenticarse a sí mismo a través del servidor (o algún otro servidor de seguridad), por ejemplo, pidiendo al usuario humano que proporcione la contraseña correcta.

Antes de la autenticación, no se aceptan las llamadas a la API.

Durante la autenticación se devuelve un "token".

Después de la autenticación, solo se aceptarán las llamadas a la API con el "token" de autenticación.

Por supuesto, en esta etapa solo los usuarios autorizados que tienen la contraseña pueden acceder a la API, aunque si son programadores que están depurando la aplicación, pueden acceder a ella directamente con fines de prueba.

  1. Segundo paso: ahora configure una API de seguridad adicional, que se llamará dentro de un corto límite de tiempo después de que la aplicación js + html del cliente se solicitó inicialmente al servidor. Esta "devolución de llamada" le dirá al servidor que el cliente se descargó correctamente. Restrinja sus llamadas a la API REST para que funcionen solo si el cliente se solicitó recientemente y con éxito.

Ahora, para usar su API, primero deben descargar el cliente y ejecutarlo en un navegador. Solo después de recibir con éxito la devolución de llamada, y luego de la entrada del usuario en un corto período de tiempo, la API aceptará llamadas.

Por lo tanto, no tiene que preocuparse de que se trate de un usuario no autorizado sin credenciales.

(El título de la pregunta, '¿Cómo puedo asegurar las llamadas a la API REST?', Y de la mayor parte de lo que dice, esa es su principal preocupación, y no la pregunta literal de CÓMO se llama su API, sino POR QUIÉN, ¿correcto? )

pashute
fuente
5
El segundo punto no tiene sentido. Si un atacante necesita cargar su aplicación, lo hará (su devolución de llamada es visible). Y luego ataca.
Andrei Volgin
El punto 2 es adicional al punto 1. El atacante todavía necesita autenticación. El punto 2 solo agrega a eso la necesidad de descargar la aplicación html para ser autorizado. Por lo tanto, es imposible llamar directamente a las API sin la aplicación (presumiblemente a la que se accede y se descarga solo después de la autenticación). Que es algo que se solicitó en esta pregunta.
pashute
Simplemente puede permitir solicitudes de su dominio únicamente.
Andrei Volgin
Eso solo limita las llamadas al interior del dominio, por lo que ahora los usuarios de la aplicación de navegador javascript deben estar dentro del dominio (probablemente no sea algo que knd quisiera) y esos usuarios aún pueden llamar a la API directamente a través de curl.
pashute
2
Lo que parece pasar por alto es que TODO lo que le pida al navegador de su usuario, puede ser replicado por un atacante; para que el navegador lo haga, debe ser legible.
Eugen Rieck
1
  1. Establezca una var SESSION en el servidor cuando el cliente cargue por primera vez su index.html(o backbone.jsetc.)

  2. Verifique esta var en el lado del servidor en cada llamada a la API.

PD: esta no es una solución de "seguridad" !!! Esto es solo para aliviar la carga en su servidor para que las personas no abusen de él o "enlacen" su API desde otros sitios web y aplicaciones.

Alex
fuente
0

Esto es lo que hago:

  1. Asegure la API con un encabezado HTTP con llamadas como X-APITOKEN:

  2. Utilice variables de sesión en PHP. Disponga de un sistema de inicio de sesión y guarde el token de usuario en las variables de sesión.

  3. Llame al código JS con Ajax a PHP y use la variable de sesión con curl para llamar a la API. De esa manera, si la variable de sesión no está configurada, no llamará y el código PHP contiene el token de acceso a la API.

Pavneet Singh
fuente