Solución:
Esta pregunta se ha abordado, en una forma ligeramente diferente, en detalle, aquí:
Autenticación RESTful
Pero esto lo aborda desde el lado del servidor. Veamos esto desde el lado del cliente. Sin embargo, antes de hacer eso, hay un preludio importante:
Javascript Crypto no tiene esperanza
El artículo de Matasano sobre esto es famoso, pero las lecciones que contiene son bastante importantes:
https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/
Para resumir:
- Un ataque man-in-the-middle puede reemplazar trivialmente su código criptográfico con
<script>
function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script> - Un ataque man-in-the-middle es trivial contra una página que sirve a cualquier recurso a través de una conexión que no sea SSL.
- Una vez que tenga SSL, de todos modos estará usando criptografía real.
Y para agregar un corolario propio:
- Un ataque XSS exitoso puede resultar en que un atacante ejecute código en el navegador de su cliente, incluso si está usando SSL, por lo que incluso si tiene todas las escotillas protegidas, la criptografía de su navegador aún puede fallar si su atacante encuentra una manera de ejecutar cualquier código javascript en el navegador de otra persona.
Esto hace que muchos esquemas de autenticación RESTful sean imposibles o tontos si tiene la intención de usar un cliente JavaScript. ¡Miremos!
Autenticación básica HTTP
En primer lugar, HTTP Basic Auth. El más simple de los esquemas: simplemente pase un nombre y una contraseña con cada solicitud.
Esto, por supuesto, requiere absolutamente SSL, porque está pasando un nombre y una contraseña codificados en Base64 (reversiblemente) con cada solicitud. Cualquiera que escuche en la línea podría extraer el nombre de usuario y la contraseña de manera trivial. La mayoría de los argumentos “La autenticación básica es insegura” provienen de un lugar de “Autenticación básica sobre HTTP”, lo cual es una idea terrible.
El navegador proporciona soporte de autenticación básica HTTP integrado, pero es feo como un pecado y probablemente no debería usarlo para su aplicación. Sin embargo, la alternativa es ocultar el nombre de usuario y la contraseña en JavaScript.
Esta es la solución más RESTful. El servidor no requiere ningún conocimiento del estado y autentica cada interacción individual con el usuario. Algunos entusiastas de REST (en su mayoría hombres de paja) insisten en que mantener cualquier tipo de estado es una herejía y se echará espuma por la boca si piensa en cualquier otro método de autenticación. Hay beneficios teóricos para este tipo de cumplimiento de estándares – es compatible con Apache listo para usar – ¡podría almacenar sus objetos como archivos en carpetas protegidas por archivos .htaccess si su corazón lo desea!
los problema? Está almacenando en caché en el lado del cliente un nombre de usuario y una contraseña. Esto le da a evil.ru una mejor solución: incluso las vulnerabilidades XSS más básicas podrían hacer que el cliente transmita su nombre de usuario y contraseña a un servidor malvado. Puede intentar aliviar este riesgo aplicando hash y agregando sal a la contraseña, pero recuerde: JavaScript Crypto no tiene esperanza. Puede aliviar este riesgo dejándolo en manos del soporte de autenticación básica del navegador, pero … feo como el pecado, como se mencionó anteriormente.
Autenticación HTTP Digest
¿Es posible la autenticación implícita con jQuery?
Una autenticación más “segura”, es un desafío de hash de solicitud / respuesta. Excepto JavaScript Crypto no tiene esperanza, por lo que solo funciona a través de SSL y aún tiene que almacenar en caché el nombre de usuario y la contraseña en el lado del cliente, lo que lo hace más complicado que HTTP Basic Auth pero no más seguro.
Autenticación de consultas con parámetros de firma adicionales.
Otra autenticación más “segura”, en la que encripta sus parámetros con datos de tiempo y nonce (para protegerse contra ataques repetidos y de tiempo) y envía el archivo. Uno de los mejores ejemplos de esto es el protocolo OAuth 1.0, que es, hasta donde yo sé, una forma bastante impresionante de implementar la autenticación en un servidor REST.
http://tools.ietf.org/html/rfc5849
Oh, pero no hay ningún cliente OAuth 1.0 para JavaScript. ¿Por qué?
JavaScript Crypto no tiene esperanza, recordar. JavaScript no puede participar en OAuth 1.0 sin SSL, y aún debe almacenar el nombre de usuario y la contraseña del cliente localmente, lo que lo coloca en la misma categoría que la autenticación implícita, es más complicado que la autenticación básica HTTP, pero es no más seguro.
Simbólico
El usuario envía un nombre de usuario y una contraseña y, a cambio, obtiene un token que puede usarse para autenticar solicitudes.
Esto es un poco más seguro que la autenticación básica HTTP, porque tan pronto como se complete la transacción de nombre de usuario / contraseña, puede descartar los datos confidenciales. También es menos RESTful, ya que los tokens constituyen el “estado” y hacen que la implementación del servidor sea más complicada.
SSL todavía
Sin embargo, el problema es que todavía tiene que enviar ese nombre de usuario y contraseña iniciales para obtener un token. La información confidencial todavía afecta a su JavaScript comprometido.
Para proteger las credenciales de su usuario, aún necesita mantener a los atacantes fuera de su JavaScript, y aún necesita enviar un nombre de usuario y contraseña por cable. Se requiere SSL.
Caducidad del token
Es común aplicar políticas de tokens como “oye, cuando este token ha existido demasiado tiempo, deséchalo y haz que el usuario se autentique nuevamente”. o “Estoy bastante seguro de que la única dirección IP permitida para usar este token es XXX.XXX.XXX.XXX
Muchas de estas políticas son ideas bastante buenas.
Firesheeping
Sin embargo, usar un token sin SSL sigue siendo vulnerable a un ataque llamado ‘sidejacking’: http://codebutler.github.io/firesheep/
El atacante no obtiene las credenciales de su usuario, pero aún puede pretender ser su usuario, lo que puede ser bastante malo.
tl; dr: Enviar tokens sin cifrar a través del cable significa que los atacantes pueden capturar fácilmente esos tokens y pretender ser su usuario. FireSheep es un programa que lo hace muy fácil.
Una zona separada y más segura
Cuanto más grande sea la aplicación que está ejecutando, más difícil será asegurarse absolutamente de que no podrán inyectar algún código que cambie la forma en que procesa los datos confidenciales. ¿Confías absolutamente en tu CDN? ¿Tus anunciantes? ¿Tu propia base de código?
Común para los detalles de la tarjeta de crédito y menos común para el nombre de usuario y la contraseña: algunos implementadores mantienen la ‘entrada de datos confidenciales’ en una página separada del resto de su aplicación, una página que se puede controlar y bloquear de la mejor manera posible, preferiblemente una que es difícil hacer phishing a los usuarios.
Cookie (solo significa Token)
Es posible (y común) colocar el token de autenticación en una cookie. Esto no cambia ninguna de las propiedades de autenticación con el token, es más una cuestión de conveniencia. Todos los argumentos anteriores siguen siendo válidos.
Sesión (todavía solo significa Token)
La autenticación de sesión es solo autenticación de token, pero con algunas diferencias que hacen que parezca algo ligeramente diferente:
- Los usuarios comienzan con un token no autenticado.
- El backend mantiene un objeto de ‘estado’ que está vinculado al token de un usuario.
- El token se proporciona en una cookie.
- El entorno de la aplicación abstrae los detalles de usted.
Sin embargo, aparte de eso, no es diferente de Token Auth, en realidad.
Esto se aleja aún más de una implementación RESTful: con los objetos de estado, avanza más y más en el camino de RPC simple en un servidor con estado.
OAuth 2.0
OAuth 2.0 analiza el problema de “¿Cómo el Software A le da al Software B acceso a los datos del Usuario X sin que el Software B tenga acceso a las credenciales de inicio de sesión del Usuario X?”.
La implementación es en gran medida una forma estándar para que un usuario obtenga un token, y luego para que un servicio de terceros diga “sí, este usuario y este token coinciden, y ahora puede obtener algunos de sus datos de nosotros”.
Sin embargo, fundamentalmente, OAuth 2.0 es solo un protocolo de token. Exhibe las mismas propiedades que otros protocolos de tokens (aún necesita SSL para proteger esos tokens), simplemente cambia la forma en que se generan esos tokens.
Hay dos formas en que OAuth 2.0 puede ayudarlo:
- Proporcionar autenticación / información a otros
- Obtener autenticación / información de otros
Pero cuando se trata de eso, solo estás … usando tokens.
De vuelta a tu pregunta
Entonces, la pregunta que se está haciendo es “¿debo almacenar mi token en una cookie y hacer que la administración automática de sesiones de mi entorno se encargue de los detalles, o debo almacenar mi token en Javascript y manejar esos detalles yo mismo?”
Y la respuesta es: Haz lo que sea que te haga feliz.
Sin embargo, lo que pasa con la gestión automática de sesiones es que hay mucha magia detrás de escena para ti. A menudo, es mejor tener el control de esos detalles usted mismo.
Tengo 21 años, así que SSL es sí.
La otra respuesta es: use https para todo o los bandidos robarán las contraseñas y tokens de sus usuarios.
Puede aumentar la seguridad en el proceso de autenticación utilizando JWT (Tokens web JSON) y SSL / HTTPS.
La autenticación básica / ID de sesión se puede robar a través de:
- Ataque MITM (Man-In-The-Middle) – sin SSL / HTTPS
- Un intruso que accede a la computadora de un usuario.
- XSS
Al usar JWT, está encriptando los detalles de autenticación del usuario y almacenándolos en el cliente, y enviándolos junto con cada solicitud a la API, donde el servidor / API valida el token. No se puede descifrar / leer sin la clave privada (que el servidor / API almacena en secreto) Leer actualización.
El nuevo flujo (más seguro) sería:
Acceso
- El usuario inicia sesión y envía las credenciales de inicio de sesión a la API (sobre SSL / HTTPS)
- API recibe credenciales de inicio de sesión
- Si es válido:
- Registre una nueva sesión en la base de datos Leer actualización
- Cifre el ID de usuario, el ID de sesión, la dirección IP, la marca de tiempo, etc. en un JWT con una clave privada.
- La API envía el token JWT al cliente. (sobre SSL / HTTPS)
- El cliente recibe el token JWT y lo almacena en localStorage / cookie
Cada solicitud a la API
- El usuario envía una solicitud HTTP a la API (sobre SSL / HTTPS) con el token JWT almacenado en el encabezado HTTP
- La API lee el encabezado HTTP y descifra el token JWT con su clave privada
- La API valida el token JWT, hace coincidir la dirección IP de la solicitud HTTP con la del token JWT y verifica si la sesión ha expirado.
- Si es válido:
- Devolver respuesta con contenido solicitado
- Si no es válido:
- Lanzar excepción (403/401)
- Marcar intrusión en el sistema
- Envíe un correo electrónico de advertencia al usuario.
Actualizado el 30.07.15:
La carga útil / reclamaciones de JWT en realidad se pueden leer sin la clave privada (secreta) y no es seguro almacenarla en localStorage. Lamento estas declaraciones falsas. Sin embargo, parecen estar trabajando en un estándar JWE. (Cifrado web JSON).
Implementé esto almacenando reclamos (ID de usuario, exp) en un JWT, lo firmé con una clave privada (secreta) que la API / backend solo conoce y lo almacené como una cookie HttpOnly segura en el cliente. De esa manera, no se puede leer a través de XSS y no se puede manipular; de lo contrario, el JWT falla en la verificación de la firma. También usando un Secure HttpOnly galleta, estas haciendo asegúrese de que la cookie se envíe solo a través de solicitudes HTTP (no accesible para el script) y solo se envíe a través de una conexión segura (HTTPS).
Actualizado 17.07.16:
Los JWT son por naturaleza apátridas. Eso significa que se invalidan / caducan. Al agregar SessionID en las afirmaciones del token, lo hace con estado, porque su validez ahora no solo depende de la verificación de la firma y la fecha de vencimiento, sino que también depende del estado de la sesión en el servidor. Sin embargo, la ventaja es que puede invalidar tokens / sesiones fácilmente, lo que antes no podía con los JWT sin estado.
Yo optaría por el segundo, el sistema de fichas.
¿Sabías sobre ember-auth o ember-simple-auth? Ambos usan el sistema basado en tokens, como los estados ember-simple-auth:
Una biblioteca ligera y discreta para implementar la autenticación basada en token en aplicaciones Ember.js. http://ember-simple-auth.simplabs.com
Tienen administración de sesiones y también son fáciles de conectar a proyectos existentes.
También hay una versión de ejemplo de Ember App Kit de ember-simple-auth: ejemplo funcional de ember-app-kit usando ember-simple-auth para la autenticación OAuth2.