web-services - servicios - rest api tutorial español
Restful servicio web de autenticación (4)
Los servicios web de Amazon lo hacen bien, revisa la metodología para algunas ideas. Básicamente, hacen que los clientes encripten un encabezado http especial usando su contraseña.
Aquí está el enlace:
http://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
Tengo una API de servicio web relajante, que está siendo utilizada por diferentes terceros. Parte de esa API está restringida (se necesita nombre de usuario / contraseña para acceder a ella). Me preguntaba ¿cuál sería la mejor forma de implementar la autenticación?
Estoy usando https, entonces la comunicación está encriptada. Tengo dos ideas:
- Antes de que el usuario comience a usar el servicio (restringido), envía un nombre de usuario / contraseña usando POST (desde que se usan las credenciales https están encriptadas). Después de que el inicio de sesión sea exitoso, el servidor devuelve un valor aleatorio de un solo uso (nonce) que coincide con este nombre de usuario. Cuando se realiza la próxima solicitud, junto con un nombre de usuario, el cliente envía el código de acceso devuelto previamente. Los servidores coinciden con el nombre de usuario y el nonce y devuelven el nuevo nonce junto con los datos solicitados. Cada nueva solicitud usa new nonce. Básicamente, esta es una versión ligera de autenticación de acceso Digest.
- Como esta API se usa desde un tercero, el nombre de usuario / contraseña se puede usar para cada solicitud (restringida). Como https se está utilizando, se cifrarán. La caída de este enfoque es el hecho de que esto no cumpliría con Restful (el POST se usaría siempre).
Estoy mucho más cerca de elegir el primer enfoque (es compatible con Restful, relativamente fácil de implementar, XML, json o html pueden usarse sin cambiar nada), pero quería ver cuál es su opinión. ¿Qué recomienda: primero, segundo o algún tercer enfoque?
Por cierto, estoy usando Python en el lado del servidor.
No hay ninguna razón para no solo usar la autenticación HTTP aquí.
Dicho esto, el concepto de POSTing para obtener un bloqueo de tiempo puede funcionar bien. Pero son las motivaciones de por qué tendrías que pasar por ese aro adicional en primer lugar.
Se consideró esta técnica cuando se usa un hash bcrypt para la contraseña original, debido al gasto real de validación de un usuario (si no se sabe, bcrypt se puede ajustar para que tome mucho tiempo real para realizar la función hash). La elección fue proporcionar la opción de hacer que el servicio "inicie sesión" una vez usando la contraseña que pasaría por el proceso de validación costoso a través de bcrypt, y luego obtendría un token bloqueado en el tiempo a cambio de futuras solicitudes que omitirían el proceso bcrypt .
En el caso del proceso bcrypt, use HTTP Authentication; el servicio funcionaría tanto con la contraseña normal como con el token. De esa forma, el usuario siempre puede usar la contraseña para su servicio, pero simplemente se vuelve costoso. Entonces PUEDEN hacer esto, simplemente NO DEBERÍAN. Al servicio no le importa qué técnica de autenticación usa el cliente.
El servicio nonce se ofrece como un aparte para mejorar el rendimiento.
Aparte de eso, es una autenticación HTTP estándar, pero con un nuevo esquema.
Suponiendo que el servicio nunca se consume en un navegador y la comunicación se cifra de todos modos, no veo ningún daño en una variación del segundo método: agregue X-Headers para enviar nombre de usuario / contraseña con cada solicitud, por ejemplo:
GET /foo HTTP/1.1
Host: www.bar.com
X-MyUsername: foo
X-MyPassword: bar
Otra idea sería usar HTTP Basic Auth y simplemente enviar una Authorization: Basic base64(user:password)
-Header. Es decir, si la conexión siempre está encriptada.
Una forma en que he visto esto hecho en las API (y la forma en que actualmente lo estoy implementando) es crear un recurso RESTful llamado Session que se crea a través de un POST que proporciona un nombre de usuario y una contraseña.
Aquí es básicamente cómo lo he implementado:
POST /sessions { Username: "User", Password: "Password" }
Cree una sesión de tiempo limitado y devuelve el recurso de sesión que contiene el valor y la caducidad de la clave de sesión. También puede devolver esto como un valor de cookie para la conveniencia de la implementación de clientes API.
DELETE /session/{id}
Inmediatamente vence la sesión por lo que ya no se puede usar. Esto se usa para salidas explícitas.
Luego pido al usuario que adjunte la clave de sesión a través de un parámetro de consulta, aunque también puede permitir que se envíe a través de un valor de cookie, recomendaría permitir ambas.
Lo que prefiero sobre esto es que es extremadamente simple.
Obviamente, su escenario dictará de alguna manera cómo deben administrarse sus sesiones, tal vez no tengan un límite de tiempo y sean de duración indefinida, y tal vez estén codificadas o cifradas para mayor seguridad.
Si está utilizando HTTPS en todas partes, probablemente no tenga que preocuparse demasiado. Sin embargo, si desea utilizar HTTP, deberá usar algo así como un hash junto con una clave secreta y decir una marca de tiempo para generar una clave segura por solicitud. De esta forma, puede compartir la clave secreta a través de HTTPS y luego cambiar a HTTP para realizar más llamadas. Incluso si alguien logra olfatear la clave de una solicitud, puede caducar casi de inmediato y ser inútil.
Descargo de responsabilidad: no soy un experto en seguridad ;-).