如何设计一个允许跨域脚本安全的JavaScript API?

时间:2010-10-30 22:00:12

标签: javascript api-design

我喜欢Google Maps'api的使用方式,使用脚本包含,但我很担心:

我的api是“半私有的”,即可通过互联网访问,但应允许安全传输数据和某种身份验证。数据应该通过网络保持私密,一个消费者不应该获得另一个数据。

如何使用SSL和某种身份验证来保证数据安全,但仍可从纯HTML页面“水平”访问,而无需服务器端代理?我需要管理密钥吗?如何在不截获的情况下将密钥发布到服务器?我可以使用OpenId(或其他一些第三方身份验证)来验证api用户,还是必须创建自己的身份验证机制?我一直在谷歌,无法找到安全设计和部署API的良好指南。

现在我正在使用REST和AJAX来使用它们,但跨域调用是不可能的。任何帮助或正确方向的指针都将非常感激。

5 个答案:

答案 0 :(得分:10)

我可能会使用动态生成的脚本标记,其中包含SSL URL,该URL包含公钥加密的查询字符串中的密钥。服务器将使用私钥来解密查询字符串参数并返回包含相关信息的脚本(如果密钥无效,则返回脚本)。或类似的规定。但我承认我实际上并没有这么做。

我也会寻找现有技术,比如亚马逊的S3服务。

所以:

  1. 用户提供秘密
  2. 客户端代码使用公钥加密秘密
  3. JavaScript附加包含网址<{li>的script标记
  4. 服务器处理脚本请求,解密密码,检查它,并发回相关的响应。
  5. 您可能需要两个周期,因为否则可以通过中间人攻击重新使用对服务器的请求。那将是:

    1. JavaScript附加一个请求唯一密钥的script标记(可能包含一些混淆信息,如源IP和一些随机的其他密钥)
    2. 服务器使用与该IP绑定的一次性密钥进行响应
    3. 用户提供秘密
    4. 客户端代码使用公钥加密秘密,包括来自#1
    5. 的唯一密钥
    6. JavaScript附加包含网址<{li>的script标记
    7. 服务器处理脚本请求,解密密码,检查它,并发回相关的响应。
    8. 使用#1
    9. 中包含的随机密钥可以对响应进行加密(在某种程度上)

      我实际上没有做过。 (或者我?BWAa-ha-ha-ha ......) FWIW。

答案 1 :(得分:0)

OAuth可能会帮助解决这种情况,方法是让用户登录第三方应用程序并允许您的应用程序在您发出xhr请求时使用请求令牌代表他们访问第三方。 http://oauth.net/documentation/getting-started/

======

使用服务器端代理的原因归结为内置于Web浏览器中的同源策略:http://en.wikipedia.org/wiki/Same_origin_policy

基本上,浏览器只允许对页面来自的地址发出请求(例如,facebook.com只能向facebook.com URI发出请求)。服务器端代理通过向当前源外的服务器发出请求来解决此问题。服务器端代理也是发出这样的请求的最佳实践。

答案 2 :(得分:0)

查看opensource javascript Forge项目。它提供了一个javascript TLS实现,允许安全的跨域xhr请求。它可能对您有用:

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

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

https://github.com/digitalbazaar/forge

一个可能的解决方案:

  1. 设置Apache服务器以运行您的站点。
  2. 获取您网站的SSL证书。
  3. 安装Forge附带的apache mod,以设置允许其他网站访问您的跨域策略。
  4. Host Forge在您网站上的TLS实施以及您网站的PEM格式证书。
  5. 告知其他网站包含您网站上的javascript,并使用它来安全地致电您的网站以执行您想要的任何操作。

答案 3 :(得分:0)

  1. (第三方)页面使用OAUTH或类似的东西来验证用户并从您的服务器获取令牌。
  2. Page从服务器加载IFRAME,通过SSL传递令牌进行身份验证。
  3. IFRAME可以通过SSL安全地与您的服务器通信
  4. 使用easyXDM或类似内容在IFRAME和第三方页面之间进行通信,使用您创建的一些类似RPC或套接字的API。
  5. 或者,如果你真的不信任第三方 - 在iframe中进行身份验证(不需要oauth,只需使用简单的html表单),并使用easyXDM与外部页面需要了解的用户进行通信。

答案 4 :(得分:0)

不太确定问题究竟是什么,我认为你试图对[https://secure.com]进行类似jsonp的调用,以便在[http://上处理/显示数据regular.com]

两台服务器可以互相通话吗?这样的事情怎么样:

  1. 用户登录[https://secure.com]

  2. 在身份验证时,secure.com会生成一个令牌(让我们称之为syntoken)并将其直接传递给regular.com(服务器到服务器),可能类似于session_id,某些任意消息和一个otp密码(我们称之为同步)。

  3. Broswer收到session_id cookie,然后Secure.com将浏览器重定向到http://regular.com/setcookieandredirect?session_id=blabla&otpencryptedsynmessage=blabla

  4. Regular.com使用session_id作为密钥查找otp密码,并解密otpencryptedmessage“blabla”。

  5. 如果解密的消息与syntoken中的原始消息匹配,我们可以验证用户是否已登录[regular.com]并且regular.com会生成另一个令牌(让我们称之为acktoken,lolz)并将其直接传递给[ secure.com],由session_id,一些任意的ack消息和一个不同的otp密码组成(让我们称之为ackcipher)。

  6. 然后,Regular.com会向浏览器发送一个由otpencryptedackmessage组成的cookie(让我们将此cookie命名为“verified_session”)。

  7. 完成加载页面。

  8. 从那里,你可以进行类似jsonp的调用

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

    其中secure.com/getscript.js将采用verifiedtoken,根据[secure.com]发送的原始cookie session_id作为密钥查找ackcipher,并解密otpencrypedackmessage。如果解密的消息与ack消息匹配,则呈现脚本文件。

    这有点像三次握手。秘诀是服务器必须能够直接相互通信以离散地传递密钥。您不必为两个服务器使用相同的session_id,我只是使用它作为一个简单的参考点来找到访问syn / ack otp密码的方法。密码必须完全隐藏在公众面前。