restful-authentication - sistema - laravel passport tutorial español
Autenticación REST y exposición de la clave API (6)
Esta pregunta tiene una respuesta aceptada, pero solo para aclarar, la autenticación secreta compartida funciona así:
- El cliente tiene una clave pública, esto se puede compartir con cualquier persona, no importa, por lo que puede incrustarlo en javascript. Esto se usa para identificar al usuario en el servidor.
- El servidor tiene una clave secreta y este secreto DEBE estar protegido. Por lo tanto, la autenticación de clave compartida requiere que pueda proteger su clave secreta. Por lo tanto, un cliente de javascript público que se conecta directamente a otro servicio no es posible porque necesita un intermediario de servidor para proteger el secreto.
- La solicitud de firma de servidor utiliza un algoritmo que incluye la clave secreta (la clave secreta es similar a una sal) y, preferiblemente, una marca de tiempo y luego envía la solicitud al servicio. La marca de tiempo es para evitar ataques de "repetición". La firma de una solicitud solo es válida por alrededor de n segundos. Puede verificarlo en el servidor obteniendo el encabezado de la marca de tiempo que debe contener el valor de la marca de tiempo que se incluyó en la firma. Si esa marca de tiempo expiró, la solicitud falla.
- El servicio recibe la solicitud que contiene no solo la firma, sino también todos los campos que se firmaron en texto sin formato.
- El servicio firma la solicitud de la misma manera con la clave secreta compartida y compara las firmas.
He estado leyendo sobre REST y hay muchas preguntas sobre SO al respecto, así como en muchos otros sitios y blogs. Aunque nunca he visto esta pregunta específica ... por alguna razón, no puedo entender este concepto ...
Si estoy construyendo una API RESTful, y quiero protegerla, uno de los métodos que he visto es usar un token de seguridad. Cuando he usado otras API, ha habido un token y un secreto compartido ... tiene sentido. Lo que no entiendo es que las solicitudes para una operación de servicio de descanso se realizan a través de javascript (XHR / Ajax), lo que es para evitar que alguien lo detecte con algo simple como FireBug (o "ver fuente" en el navegador) y copiando la clave API, y luego suplantando a esa persona usando la clave y el secreto?
Estamos exponiendo una API que los socios solo pueden usar en los dominios que han registrado con nosotros. Su contenido es en parte público (pero preferiblemente solo para mostrarse en los dominios que conocemos), pero es principalmente privado para nuestros usuarios. Asi que:
Para determinar lo que se muestra, nuestro usuario debe haber iniciado sesión con nosotros, pero esto se maneja por separado.
Para determinar dónde se muestran los datos, se utiliza una clave API pública para limitar el acceso a los dominios que conocemos y, sobre todo, para garantizar que los datos de los usuarios privados no sean vulnerables a CSRF .
Esta clave de API es visible para todos, no autenticamos a nuestro socio de ninguna otra manera y no necesitamos REFERER . Aún así, es seguro:
Cuando
get-csrf-token.js?apiKey=abc123
nuestroget-csrf-token.js?apiKey=abc123
:Busque la clave
abc123
en la base de datos y obtenga una lista de dominios válidos para esa clave.Busque la cookie de validación de CSRF. Si no existe, genere un valor aleatorio seguro y colóquelo en una cookie de sesión de solo HTTP . Si la cookie existió, obtenga el valor aleatorio existente.
Cree un token CSRF a partir de la clave API y el valor aleatorio de la cookie, y fírmelo . (En lugar de mantener una lista de tokens en el servidor, estamos firmando los valores. Ambos valores serán legibles en el token firmado, está bien).
Establezca la respuesta para que no se almacene en caché, agregue la cookie y devuelva un script como:
var apiConfig = apiConfig || {}; if(document.domain === ''expected-domain.com'' || document.domain === ''www.expected-domain.com'') { apiConfig.csrfToken = ''API key, random value, signature''; // Invoke a callback if the partner wants us to if(typeof apiConfig.fnInit !== ''undefined'') { apiConfig.fnInit(); } } else { alert(''This site is not authorised for this API key.''); }
Notas:
Lo anterior no impide que una secuencia de comandos del lado del servidor falsifique una solicitud, pero solo asegura que el dominio coincida si lo solicita un navegador.
La misma política de origen para JavaScript garantiza que un navegador no pueda usar XHR (Ajax) para cargar e inspeccionar la fuente de JavaScript. En cambio, un navegador normal solo puede cargarlo usando
<script src="https://our-api.com/get-csrf-token.js?apiKey=abc123">
(o un equivalente dinámico), y luego ejecutará el código. Por supuesto, su servidor no debería admitir el Intercambio de recursos de origen cruzado ni JSONP para el JavaScript generado.Una secuencia de comandos del navegador puede cambiar el valor de
document.domain
antes de cargar la secuencia de comandos anterior. Pero la misma política de origen solo permite acortar el dominio eliminando prefijos, como reescribirsubdomain.example.com
a soloexample.com
, omyblog.wordpress.com
awordpress.com
, o en algunos navegadores inclusobbc.co.uk
aco.uk
Si el archivo JavaScript se obtiene utilizando algún script del lado del servidor, el servidor también obtendrá la cookie. Sin embargo, un servidor de terceros no puede hacer que el navegador de un usuario asocie esa cookie a nuestro dominio. Por lo tanto, un token CSRF y una cookie de validación que se han obtenido utilizando un script del lado del servidor, solo pueden ser utilizados por las llamadas posteriores del lado del servidor, no en un navegador. Sin embargo, tales llamadas del lado del servidor nunca incluirán la cookie de usuario y, por lo tanto, solo pueden obtener datos públicos. Esta es la misma información que un script del lado del servidor podría eliminar directamente del sitio web del socio.
Cuando un usuario inicia sesión, configure algunas cookies de usuario de la forma que desee. (Es posible que el usuario ya haya iniciado sesión antes de solicitar JavaScript).
Todas las solicitudes API posteriores al servidor (incluidas las solicitudes GET y JSONP) deben incluir el token CSRF, la cookie de validación CSRF y (si está registrada) la cookie del usuario. El servidor ahora puede determinar si la solicitud es confiable:
La presencia de un token CSRF válido garantiza que JavaScript se cargó desde el dominio esperado, si lo carga un navegador.
La presencia del token CSRF sin la cookie de validación indica falsificación.
La presencia del token CSRF y la cookie de validación CSRF no aseguran nada: esto podría ser una solicitud forjada del lado del servidor o una solicitud válida de un navegador. (No podría ser una solicitud de un navegador hecho desde un dominio no compatible).
La presencia de la cookie de usuario garantiza que el usuario haya iniciado sesión, pero no garantiza que el usuario sea miembro de un socio determinado, ni que el usuario esté viendo el sitio web correcto.
La presencia de la cookie del usuario sin la cookie de validación CSRF indica falsificación.
La presencia de la cookie de usuario garantiza que la solicitud actual se realice a través de un navegador. (Suponiendo que un usuario no ingrese sus credenciales en un sitio web desconocido, y suponiendo que no nos importa que los usuarios usen sus propias credenciales para realizar alguna solicitud del lado del servidor). Si también tenemos la cookie de validación CSRF, entonces esa cookie de validación CSRF también recibido usando un navegador. A continuación, si también tenemos un token CSRF con una firma válida, y el número aleatorio en la cookie de validación CSRF coincide con el de ese token CSRF, el JavaScript de ese token también se recibió durante esa misma solicitud anterior durante la cual el CSRF cookie se estableció, por lo tanto, también utilizando un navegador. Esto también implica que el código JavaScript anterior se ejecutó antes de que se configurara el token, y que en ese momento el dominio era válido para la clave API dada.
Entonces: el servidor ahora puede usar de forma segura la clave API del token firmado.
Si en algún momento el servidor no confía en la solicitud, se devuelve un 403 Prohibido. El widget puede responder mostrando una advertencia al usuario.
No es necesario que firme la cookie de validación CSRF, ya que la estamos comparando con el token CSRF firmado. No firmar la cookie hace que cada solicitud HTTP sea más corta y la validación del servidor un poco más rápida.
El token CSRF generado es válido indefinidamente, pero solo en combinación con la cookie de validación, de manera efectiva hasta que se cierre el navegador.
Podríamos limitar el tiempo de vida de la firma del token. Podríamos eliminar la cookie de validación de CSRF cuando el usuario cierre la sesión, para cumplir con la recomendación de OWASP . Y para no compartir el número aleatorio por usuario entre varios socios, se podría agregar la clave API al nombre de la cookie. Pero incluso así, uno no puede actualizar fácilmente la cookie de validación CSRF cuando se solicita un nuevo token, ya que los usuarios pueden estar navegando en el mismo sitio en varias ventanas, compartiendo una única cookie (que, al actualizar, se actualizaría en todas las ventanas, después del cual JavaScript token en las otras ventanas ya no coincidiría con esa única cookie).
Para aquellos que usan OAuth, vea también OAuth y Widgets del lado del cliente , de donde obtuve la idea de JavaScript. Para el uso del lado del servidor de la API, en la que no podemos confiar en el código JavaScript para limitar el dominio, estamos utilizando claves secretas en lugar de las claves API públicas.
Lo que desea hacer en el lado del servidor es generar un ID de sesión vencido que se devuelve al cliente al iniciar sesión o registrarse. El cliente puede usar esa identificación de sesión como un secreto compartido para firmar solicitudes posteriores.
La identificación de la sesión solo se pasa una vez y esto DEBE ser a través de SSL.
Ver ejemplo here
Use un nonce y sello de tiempo al firmar la solicitud para evitar el secuestro de la sesión.
Supongo que te refieres a la clave de sesión, no a la clave de API. Ese problema se hereda del protocolo http y se conoce como secuestro de sesión . La "solución alternativa" normal es, como en cualquier sitio web, cambiar a https.
Para ejecutar el servicio REST seguro debe habilitar https, y probablemente la autenticación del cliente. Pero, después de todo, esto está más allá de la idea de REST. REST nunca habla de seguridad.
Trataré de responder la pregunta en su contexto original. Entonces la pregunta es "¿Es segura la clave secreta (API) para colocarse en JavaScript?
En mi opinión, es muy inseguro ya que derrota el propósito de la autenticación entre los sistemas. Dado que la clave estará expuesta al usuario, el usuario puede recuperar información a la que no está autorizado. Porque en un descanso típico, la autenticación de comunicación solo se basa en la clave API.
Una solución, en mi opinión, es que la llamada a JavaScript esencialmente pasa la solicitud a un componente interno del servidor que es responsable de realizar una llamada de descanso. El componente interno del servidor digamos que un Servlet leerá la clave API desde una fuente segura como el sistema de archivos basado en permisos, insertará en el encabezado HTTP y realizará la llamada de descanso externa.
Espero que esto ayude.
api secret no se pasa explícitamente, secret se usa para generar un signo de solicitud actual, en el servidor, el servidor genera el signo siguiendo el mismo proceso, si los dos signos coinciden, entonces la solicitud se autentica con éxito, por lo que solo el el signo se pasa a través de la solicitud, no el secreto.