最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

How can I design a javascript API that allows for cross-domain scripting securely? - Stack Overflow

programmeradmin0浏览0评论

I like the way Google Maps' api is consumed, using a script include, but I'm worried:

My api is "semi-private", that is, accessible over the internet but should allow for secure transmission of data and some kind of authentication. The data should remain private over the wire, and one consumer shouldn't be able to get at another's data.

How can I use SSL and some kind of authentication to keep the data secure, but still accessible "horizontally" from a plain HTML page with no server-side proxy required? Do I need to manage keys? How will the keys be posted to the server without being intercepted? Can I use OpenId (or some other 3rd-party authentication) to authenticate api users, or do I have to create my own authentication mechanism? I've been all over Google and can't find a good guide to designing and deploying my API securely.

Right now I'm using REST and AJAX to consume them, but cross-domain calls are impossible. Any help or a pointer in the right direction would be much appreciated.

I like the way Google Maps' api is consumed, using a script include, but I'm worried:

My api is "semi-private", that is, accessible over the internet but should allow for secure transmission of data and some kind of authentication. The data should remain private over the wire, and one consumer shouldn't be able to get at another's data.

How can I use SSL and some kind of authentication to keep the data secure, but still accessible "horizontally" from a plain HTML page with no server-side proxy required? Do I need to manage keys? How will the keys be posted to the server without being intercepted? Can I use OpenId (or some other 3rd-party authentication) to authenticate api users, or do I have to create my own authentication mechanism? I've been all over Google and can't find a good guide to designing and deploying my API securely.

Right now I'm using REST and AJAX to consume them, but cross-domain calls are impossible. Any help or a pointer in the right direction would be much appreciated.

Share Improve this question asked Oct 30, 2010 at 22:00 Chris McCallChris McCall 10.4k9 gold badges50 silver badges82 bronze badges 9
  • 1 One tiny issue - how do You expect keys or passwords to be secure when the client is in javascript? all "semi privacy" is transparent to anybody who peeks at code. – naugtur Commented Nov 9, 2010 at 12:05
  • He could generate client-side certificates and store them using flash/HTML5 local storage... and then have websites pass parameters via a URL or window.name to an iframe that will use the certificate in a secure call to fetch whatever data is to be displayed in the iframe (to avoid having to use cookies or a login process). – dlongley Commented Nov 9, 2010 at 16:53
  • @naugtur: that's why I'm posting the question :) – Chris McCall Commented Nov 9, 2010 at 17:46
  • Doing it with user keys is just creating new bugs. I'd just use https and start a session with a consumer log-in. Customers can't access each others' data and there's https. [sessions work cross-site, so only thing to the client has to do is pass the cookie to his user after he logs in with CURL] I've never done anything like that, but it should work – naugtur Commented Nov 10, 2010 at 9:50
  • Your question is way too vague, this is a 3 or 4 part scenario (your site, other site, user and possibly 4th part attacker), that opens a tremendous amount of attack vectors, we need to establish who is trusted in what respect. You better just describe the entire task in detail. – aaaaaaaaaaaa Commented Nov 11, 2010 at 16:29
 |  Show 4 more comments

5 Answers 5

Reset to default 10 +300

I'd probably use a dynamically-generated script tag with an SSL URL that included a key in the query string that was public-key encrypted. The server would use the private key to decrypt the query string parameter and return script that included the relevant information (or didn't, if the key was invalid). Or something along those lines. But I'll admit that I haven't actually had to do it in practice.

I'd also look for prior art, like Amazon's S3 service.

So:

  1. User provides secret
  2. Client-side code uses public key to encrypt the secret
  3. JavaScript appends a script tag that includes the URL
  4. Server handles the script request, decrypts the secret, checks it, and sends back the relevant response.

You may well need two cycles, because otherwise the request to the server could be re-used via a man-in-the-middle attack. That would be:

  1. JavaScript appends a script tag that requests a unique key (probably with some confounding information, like the source IP and some random further key)
  2. Server responds with a one-time key tied to that IP
  3. User provides secret
  4. Client-side code uses public key to encrypt the secret, including the unique key from #1
  5. JavaScript appends a script tag that includes the URL
  6. Server handles the script request, decrypts the secret, checks it, and sends back the relevant response.
  7. The response could well be encrypted (to some degree) using the random key included in #1

None of which I've actually done. (Or have I? BWAa-ha-ha-ha...) FWIW.

OAuth might help with this situation by having the user login to the 3rd-party application and allowing your application to access the 3rd-party on their behalf by using a request token when you make xhr requests. http://oauth.net/documentation/getting-started/

========

The reason for using a server-side proxy boils down to the Same-origin policy built into web browsers: http://en.wikipedia.org/wiki/Same_origin_policy

Essentially the browser only allows requests to be made to the address in which the page comes from (e.g. facebook.com can only make requests to facebook.com URIs). A server-side proxy solves this issue by making requests to servers outside the current origin. Server-side proxies are also the best practice for making requests like this.

Check out the opensource javascript Forge project. It provides a javascript TLS implementation that allows secure cross-domain xhr requests. It might be of use to you:

http://digitalbazaar.com/2010/07/20/javascript-tls-1/

http://digitalbazaar.com/2010/07/20/javascript-tls-2/

https://github.com/digitalbazaar/forge

One potential solution:

  1. Set up an Apache server to run your site.
  2. Get an SSL certificate for your site.
  3. Install the apache mod that comes with Forge to setup a cross-domain policy that allows other sites to access yours.
  4. Host Forge's TLS implementation on your site along with your site's certificate in PEM format.
  5. Tell other sites to include the javascript from your site and use it to make secure calls to your site to do whatever it is you want to.
  1. (3rd party) Page uses OAUTH or something similar to authenticate the user and get a token from your server.
  2. Page loads an IFRAME from your server via SSL passing the token along for authentication.
  3. The IFRAME can communicate securely to your server via SSL
  4. Use easyXDM or something similar to communicate between the IFRAME and the 3rd party page, using some limited RPC-like or socket-like API you create.

Or if you really don't trust the third party - do your authentication inside the iframe (no need for oauth then, just use a plain html form) and communicate anything the outer page needs to know about the user using easyXDM.

Not too sure of what the question is exactly, I take it you're attempting to do a jsonp-like call to [https://secure.com] in order to process/display data on [http://regular.com]?

Can the two servers talk to each other? How about something like this:

  1. User logs in on [https://secure.com]

  2. Upon authentication, secure.com generates an token (lets call it syntoken) and passes it directly to regular.com (server-to-server), maybe like a session_id, some arbitrary message, and an otp cipher (lets call it syncipher).

  3. Broswer receives a session_id cookie, and Secure.com then redirects the browser to http://regular.com/setcookieandredirect?session_id=blabla&otpencryptedsynmessage=blabla

  4. Regular.com looks up otp cipher using session_id as a key, and decrypts otpencryptedmessage "blabla."

  5. If decrypted message matches the original message in the syntoken, we can verify user is logged in [regular.com] and regular.com generates another token (lets call it acktoken, lolz) and passes it directly to [secure.com], consisting of session_id, some arbitrary ack message, and a different otp cipher (lets call it ackcipher).

  6. Regular.com then sends the browser a cookie consisting of otpencryptedackmessage (let's name this cookie "verified_session").

  7. Finish loading the page.

From there, you can do jsonp-like calls to

https://secure.com/getscript.js?query=dataname&verifiedtoken=(verified_sessions_cookie_value)

where secure.com/getscript.js will take the verifiedtoken, lookup the ackcipher based on the original cookie session_id sent by [secure.com] as the key, and decrypt the otpencrypedackmessage. If the decrypted message matches the ack message, render the script file.

It's kinda like a 3-way handshake. The secret sauce is that the servers have to be able to talk to each other directly to pass secret keys discretely. You don't have to use the same session_id for both servers, I was just using that as an easy point of reference to find a way to access the syn/ack otp ciphers. The ciphers must be completely hidden from public.

发布评论

评论列表(0)

  1. 暂无评论