在Javascript中保护OAuth

时间:2011-05-26 20:44:52

标签: javascript security oauth oauth-provider browser-extension

我有一个api,它使用OAuth 1.0a来验证使用它的应用程序。它正在取代旧的api,它使用了一些被弃用的定制和hodge-podge调用。

众所周知,OAuth 1.0a在(客户端)Javascript中并不安全,因为它依赖于保密的消费者秘密。这是不可能的,因为源始终是可见的。

我们有适用于Chrome,Firefox,IE和Safari的浏览器扩展,需要在将来使用此API。这些扩展都是大部分或完全用Javascript编写的,因此也是安全问题。

这些扩展是内部扩展的,因此可以使用自定义身份验证方法来获取其访问权限。

我计划实施的内容如下:

  • 用户在浏览器中登录网站。
  • 网站向他们发放带有会话密钥的cookie。
  • 然后我们的扩展程序接受该cookie并将其传递给api。
  • api验证它是有效的&活动会话并发布其访问令牌的扩展名。
  • 这些代币在到期前最多持续一小时。
  • javascript发布的Cookie也会有较低的费率限制。

它在以下假设下运作:

  • 如果其他应用程序可以访问您的cookie,那么无论如何他们都可以在网站上冒充您,因此访问api也不例外。
  • 所有身份验证方法仍然可以通过我们控制。
  • 令牌定期到期意味着如果他们受到损害,那么剥削的时间有限。

我的问题是,这是一种限制访问api的安全方法吗? 还有更好的吗?

一些笔记。 我知道有一个事实,Chrome扩展可以请求访问您的给定网站的cookie的权限。我相信firefox扩展也可以这样做。

显然,我们不希望我们的cookie可以通过任何页面上的javascript访问,否则我们会将自己暴露给XSS攻击,所以它们只能通过扩展来访问。

3 个答案:

答案 0 :(得分:8)

我写了一个网站,通过javascript库为OAuth登录OAuth。这是工作流程:

  1. 仅在具有LocalStorage
  2. 的浏览器上支持OAuth
  3. 如果OAuth密钥存在,登录表单将检查LocalStorage的OAuth密钥并自动尝试OAuth登录。
  4. 登录表单上有一个“记住我”的复选框,因此用户可以在登录时为他们创建OAuth令牌。
  5. 成功登录/记住我会:
    • 查找或创建名称等于User Agent的ClientApplication,并在必要时创建令牌
    • 在HTML响应中使用javascript标记进行响应。 javascript标记将调用javascript函数,并将标记作为参数传递。此功能会将OAuth令牌保存到LocalStorage。
  6. OAuth登录尝试失败将:
    • 在HTML响应中使用javascript标记进行响应。 javascript标记将调用javascript函数来清除OAuth令牌的LocalStorage设置。这将阻止其他OAuth登录尝试
  7. 这个过程还有一些细节,如果你想要我,我可以告诉你更多。

答案 1 :(得分:3)

之后来到这篇文章的人只想几点:

  1. “这是安全的” - >这取决于我们想要保护哪些威胁。我将在以下几点假设解决方案已经暗示了可信网络链接(以防止传输中的令牌或凭据拦截尝试)。但是,描述中缺少一个关键元素,因为它没有提到我们是否保护API免受未经授权的用户(人)或未经授权的API客户端(如浏览器中运行的恶意扩展)。前者可以通过可用的开放标准很容易地实现,而人们应该忘记尝试阻止未经授权的扩展访问,因为模型从根本上依赖于开源客户端技术。这与工作站安全性的关系不仅仅是设计强大的身份验证/授权机制。我们仍然可以实现某种扩展认证机制,但对于知道如何阅读扩展源代码的人来说,它将毫无用处。

  2. 我们可以通过两种方式设计平台。通过检测API以允许查询身份验证服务。或者使用基于令牌的访问,其中API将在其接收的每个请求中请求存在有效令牌而不是其发射器。这将意味着使用新角色扩展身份验证服务:API票证发行者,这很少有趣。在阅读命题时,似乎我们通过将会话令牌转发到API来合并两个世界。 这是错误的。首先,这不是基于cookie的会话令牌设计的原因。其次,它迫使API与用户认证服务的会话管理系统实现某种实时同步链接 - >我们可以轻易避免的耦合。

  3. 我将假设主要目标是保护API免受未经授权的用户的攻击,并且我们不会尝试解决依赖本地系统访问的威胁。

  4. 现在,考虑到我们不会在API中实现身份验证逻辑,我们必须依赖用户对身份验证服务进行身份验证的模型,从而使任何底层扩展都能够请求访问令牌。

  5. 这会修改原始方案,如下所示:

    • 用户使用浏览器登录网站。
    • 网站发出包含会话密钥的cookie。
    • 扩展程序现在可以向身份验证服务发送故障单请求。请求将包括会话令牌(默认浏览器行为),因此将进行身份验证。
    • 扩展程序收到故障单后,扩展程序会将其转发给API并请求会话令牌。
    • API通过询问会话管理器来验证故障单。如果会话管理器说“是,我制作了此票证且它仍然有效”,则API会生成会话令牌并将其返回到扩展名。此令牌将插入所有后续请求中,而不是票证中。这将避免会话管理器上的任何不必要的工作量。
    • 令牌(不要与票证混淆)可能会有很短的生命周期,例如几分钟 - >如果它到期,扩展只返回到身份验证服务并请求新票证(返回上面的步骤3)。
  6. 上述解决方案基本上依赖于票证和令牌的安全性。他们的设计必须至少针对以下5种威胁实施对策:i)尝试猜测票证/令牌(安全足够的随机生成),ii)尝试计算票证/令牌(足够大的熵),iii)尝试重用票证/令牌(到期),iv)尝试篡改有效票证/令牌(完整性检查),v)尝试在没有有效令牌/票证的情况下访问API(验证API接收的每个请求中的令牌) )。

  7. 这种方法的另一个优点是我们可以通过发出特定于扩展的令牌来优化资源分配,这反过来将触发API上的特定逻辑(减少API访问,减少生命周期,请求限制等)。

  8. 希望它有所帮助。

答案 2 :(得分:2)

所以你在example.com上有一个网站,它需要访问api.com。您的扩展程序假定用户已登录example.com,提取会话cookie并将其传递给api.com以获取Oauth令牌。听起来很合理,但是没有必要编写浏览器插件就有更简单的方法。

在您的情况下,api.com将与example.com通信以验证会话cookie。两个系统之间存在很强的依赖关系。 OAuth通常用于example.com和api.com互不信任的地方。

因为这两个系统已经相互信任,所以你可以做各种事情来简化架构:

  1. 您可以创建一个托管在example.com/api/*上的代理来验证会话,然后盲目地转发到api.com/*。就浏览器而言,没有跨域请求,所以一切都很好。
  2. 您可以跨域使用联合登录。这比代理方法更复杂,但您可以轻松找到适用于您平台的现有实现。