¿Cómo puedo diseñar una API de javascript que permita la creación de scripts entre dominios de forma segura?
api-design (5)
Me gusta la forma en que se consume la API de Google Maps, usando un script incluido, pero me preocupa:
Mi api es "semiprivada", es decir, accesible a través de Internet, pero debería permitir la transmisión segura de datos y algún tipo de autenticación. Los datos deben permanecer privados a través del cable, y un consumidor no debe poder obtener los datos de otro.
¿Cómo puedo usar SSL y algún tipo de autenticación para mantener los datos seguros, pero aún accesible "horizontalmente" desde una página HTML sin necesidad de un servidor proxy? ¿Necesito gestionar claves? ¿Cómo se publicarán las claves en el servidor sin ser interceptadas? ¿Puedo usar OpenId (o alguna otra autenticación de terceros) para autenticar a los usuarios de la API, o tengo que crear mi propio mecanismo de autenticación? He estado en todo Google y no puedo encontrar una buena guía para diseñar y desplegar mi API de forma segura.
En este momento estoy usando REST y AJAX para consumirlos, pero las llamadas entre dominios son imposibles. Cualquier ayuda o un puntero en la dirección correcta sería muy apreciado.
- (Terceros) La página utiliza OAUTH o algo similar para autenticar al usuario y obtener un token de su servidor.
- Page carga un IFRAME desde su servidor a través de SSL que pasa el token para la autenticación.
- El IFRAME puede comunicarse de forma segura a su servidor a través de SSL
- Use easyXDM o algo similar para comunicarse entre IFRAME y la página de terceros, usando un API limitado similar a RPC o similar a socket que cree.
O si realmente no confía en el tercero, realice su autenticación dentro del iframe (no es necesario que utilice un formulario HTML simple) y comunique todo lo que la página externa necesita saber sobre el usuario que usa easyXDM.
Echa un vistazo al proyecto de código abierto Forge javascript. Proporciona una implementación TLS de javascript que permite solicitudes xhr de dominio cruzado seguras. Podría ser de utilidad para usted:
http://digitalbazaar.com/2010/07/20/javascript-tls-1/
http://digitalbazaar.com/2010/07/20/javascript-tls-2/
https://github.com/digitalbazaar/forge
Una posible solución:
- Configure un servidor Apache para ejecutar su sitio.
- Obtenga un certificado SSL para su sitio.
- Instala el mod de apache que viene con Forge para configurar una política de dominios cruzados que permita que otros sitios accedan a los tuyos.
- La implementación TLS de Host Forge en su sitio junto con el certificado de su sitio en formato PEM.
- Indique a otros sitios que incluyan el javascript de su sitio y utilícelo para hacer llamadas seguras a su sitio para hacer lo que desee.
No muy seguro de cuál es exactamente la pregunta, supongo que está intentando hacer una llamada tipo jsonp a [https://secure.com] para procesar / mostrar datos en [http://regular.com ]?
¿Pueden los dos servidores hablar entre sí? Qué tal algo como esto:
El usuario inicia sesión en [https://secure.com]
Al autenticarse, secure.com genera un token (llamémoslo syntoken) y lo pasa directamente a regular.com (server-to-server), tal vez como session_id, algún mensaje arbitrario y un cifrado otp (llamémoslo syncipher) .
Broswer recibe una cookie de session_id y Secure.com luego redirige el navegador a http://regular.com/setcookieandredirect?session_id=blabla&otpencryptedsynmessage=blabla
Regular.com busca el cifrado otp usando session_id como clave y descifra el mensaje otpencrypted "blabla".
Si el mensaje descifrado coincide con el mensaje original en el syntoken, podemos verificar que el usuario haya iniciado sesión en [regular.com] y regular.com genere otro token (llamémoslo acktoken, lolz) y lo pase directamente a [secure.com], que consiste de session_id, algún mensaje de ack arbitrario y un cifrado otp diferente (llamémoslo ackcipher).
Regular.com luego envía al navegador una cookie que consta de otpencryptedackmessage (llamemos a esta cookie "verified_session").
Termina de cargar la página.
Desde allí, puedes hacer llamadas tipo jsonp a
https://secure.com/getscript.js?query=dataname&verifiedtoken=(verified_sessions_cookie_value )
donde secure.com/getscript.js tomará el token verificado, buscará el ackcipher según la clave original session_id enviado por [secure.com] como la clave, y descifrará el mensaje otpencrypedack. Si el mensaje descifrado coincide con el mensaje de confirmación, renderice el archivo de script.
Es un poco como un apretón de manos de 3 vías. La salsa secreta es que los servidores tienen que poder hablar entre ellos directamente para pasar las claves secretas discretamente. No tiene que usar el mismo session_id para ambos servidores, solo lo estaba usando como un punto de referencia fácil para encontrar una manera de acceder a los cifrados syn / ack otp. Los cifrados deben estar completamente ocultos del público.
OAuth puede ayudar con esta situación haciendo que el usuario inicie sesión en la aplicación de terceros y permita que su aplicación acceda a la tercera parte en su nombre mediante el uso de un token de solicitud cuando realice solicitudes xhr. http://oauth.net/documentation/getting-started/
========
La razón para usar un proxy del lado del servidor se reduce a la política del mismo origen incorporada en los navegadores web: http://en.wikipedia.org/wiki/Same_origin_policy
Esencialmente, el navegador solo permite que se realicen solicitudes a la dirección de donde proviene la página (por ejemplo, facebook.com solo puede realizar solicitudes a las URI de facebook.com). Un proxy del lado del servidor resuelve este problema al realizar solicitudes a servidores fuera del origen actual. Los proxies del lado del servidor también son la mejor práctica para realizar solicitudes como esta.
Probablemente usaría una etiqueta de script generada dinámicamente con una URL SSL que incluía una clave en la cadena de consulta que estaba encriptada con clave pública. El servidor usaría la clave privada para descifrar el parámetro de cadena de consulta y la secuencia de comandos de retorno que incluía la información relevante (o no, si la clave no era válida). O algo por el estilo. Pero debo admitir que no he tenido que hacerlo en la práctica.
También buscaría la técnica anterior, como el servicio S3 de Amazon.
Asi que:
- Usuario proporciona secreto
- El código del lado del cliente utiliza una clave pública para cifrar el secreto
- JavaScript agrega una etiqueta de
script
que incluye la URL - El servidor maneja la solicitud de script, descifra el secreto, lo verifica y envía la respuesta relevante.
Es posible que necesite dos ciclos, porque de lo contrario la solicitud al servidor podría reutilizarse a través de un ataque de intermediario. Eso sería:
- JavaScript agrega una etiqueta de
script
que solicita una clave única (probablemente con alguna información de confusión, como la IP de origen y alguna otra clave aleatoria) - El servidor responde con una clave de una sola vez vinculada a esa IP
- Usuario proporciona secreto
- El código del lado del cliente utiliza una clave pública para cifrar el secreto, incluida la clave única de # 1
- JavaScript agrega una etiqueta de
script
que incluye la URL - El servidor maneja la solicitud de script, descifra el secreto, lo verifica y envía la respuesta relevante.
- La respuesta podría estar cifrada (hasta cierto punto) utilizando la clave aleatoria incluida en el número 1
Nada de lo que realmente he hecho. (¿O tengo que? BWAa-ha-ha-ha ...) FWIW.