Javascript 中的安全 OAuth

发布于 2024-11-09 19:41:55 字数 936 浏览 4 评论 0原文

我有一个 api,它使用 OAuth 1.0a 来验证使用它的应用程序。它正在取代旧的 API,旧的 API 使用了许多自定义构建和大杂烩调用,但这些调用已被弃用。

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

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

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

我计划实现的内容如下:

  • 用户在浏览器中登录网站。
  • 该网站向他们发出一个带有会话密钥的 cookie。
  • 然后我们的扩展获取该 cookie 并将其传递给 api。
  • api 验证它是有效的 &活动会话并向扩展发出其访问令牌。
  • 这些令牌在过期前最多持续一小时。
  • javascript 发出的 cookie 的速率限制也将降低。

它在以下假设下运行:

  • 如果另一个应用程序可以访问您的 cookie,那么他们无论如何都可以在网站上冒充您,因此对 api 的访问没有什么不同。
  • 所有身份验证方法仍然受到我们的控制。
  • 代币定期过期意味着如果它们被泄露,那么利用的时间是有限的。

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

一些注释。 我知道 Chrome 扩展程序可以请求访问给定站点的 cookie 的权限。我相信 Firefox 扩展也可以做到这一点。

显然,我们不希望在任何页面上通过 javascript 访问我们的 cookie,否则我们将面临 XSS 攻击,因此它们只需要通过扩展来访问。

I have an api which uses OAuth 1.0a to authenticate applications using it. It's replacing an old api which used a number of custom built and hodge-podge calls which are being deprecated.

It's well known that OAuth 1.0a is not secure in (client-side) Javascript since it relies on the consumer secret being kept secret. Which is not possible since the source is always viewable.

We have browser extensions for Chrome, Firefox, IE and Safari which need to use this api in the future. These extensions are all written largely or entirely in Javascript, and hence the problem of security.

These extensions are in-house and so can have custom authentication methods to get their access tokens.

What I'm planning on implementing is the following:

  • The user logs into the website in the browser.
  • The website issues them a cookie with a session key.
  • Our extension then takes that cookie and passes it to the api.
  • The api validates that it is a valid & active session and issues the extension its access tokens.
  • These tokens last for a maximum of one hour before they expire.
  • There will also be lower rate limits on the javascript issued cookies.

It operates under the following assumptions:

  • If another application has access to your cookies, then they can impersonate you on the website anyway, so access to the api is no different.
  • All authentication methods still go through our control.
  • Regular expiry of tokens means that if they are compromised then there is a limited time for exploitation.

My question is, is this a secure method of restricting access to the api?
Are there any better ones?

A couple of notes.
I know for a fact that chrome extensions can ask for permission to access your cookies for a given site. I believe firefox extensions can do so too.

Obviously we don't want our cookies accessible via javascript on any page otherwise we'd expose ourselves to XSS attacks, so they need to only be accessible via extensions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

护你周全 2024-11-16 19:41:55

我编写了一个网站,通过 OAuth 的 javascript 库进行 OAuth 登录。工作流程如下:

  1. OAuth 仅在具有 LocalStorage 的浏览器上受支持
  2. 。登录表单将检查 LocalStorage 中的 OAuth 密钥,并在 OAuth 密钥存在时自动尝试 OAuth 登录。
  3. 登录表单上有一个“记住我”复选框,因此用户可以在登录时为其创建 OAuth 令牌。
  4. 成功登录并记住我将:
    • 查找或创建名称等于 User Agent 的 ClientApplication,并根据需要创建令牌
    • 在 HTML 响应中使用 javascript 标记进行响应。 javascript 标签将使用作为参数传递的标记来调用 javascript 函数。此函数会将 OAuth 令牌保存到 LocalStorage。
  5. 不成功的 OAuth 登录尝试将:
    • 在 HTML 响应中使用 javascript 标记进行响应。 javascript 标记将调用 javascript 函数来清除 OAuth 令牌的 LocalStorage 设置。这将防止额外的 OAuth 登录尝试

此过程有更多详细信息,如果您愿意,我可以告诉您更多相关信息。

I wrote a site that does OAuth login via javascript library for OAuth. This is the workflow:

  1. OAuth is only supported on browsers that have LocalStorage
  2. The login form will check LocalStorage for OAuth keys and try an OAuth login automatically if OAuth keys exist.
  3. There is a checkbox for "remember me" on login form, so a user can have OAuth tokens created for them on login.
  4. A successful login w/ remember me will:
    • find or create ClientApplication with the name equal to User Agent, and create the tokens if necessary
    • respond with a javascript tag in the HTML response. The javascript tag will call a javascript function with the tokens passed as arguments. This function will save the OAuth tokens to LocalStorage.
  5. An unsuccessful OAuth login attempt will:
    • respond with a javascript tag in the HTML response. The javascript tag will call a javascript function to clear the LocalStorage settings for OAuth tokens. This will prevent additional OAuth login attempts

There is some more detail to this process, I can tell you more about it if you want me to.

初见终念 2024-11-16 19:41:55

对于后来看到这篇文章的人来说,只有一些想法:

  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 访问、缩短生命周期、请求限制等)

希望它有所帮助。

Just a few thoughts for those coming to this post afterwards:

  1. "Is this secure" -> it depends on which threats we want to protect from. I will assume in the following points that the solution already implies a trusted network link (to prevent in-transit token or credentials interception attempts). However, a crucial element is missing in the description as it doesn't mention whether we protect the API from unauthorized users (human beings) or from unauthorized API clients (like a rogue extension running within the browser). The former can be achieved quite easily with available open standards, whereas one should forget attempting to prevent access from unauthorized extensions as the model fundamentally relies on an open-source client-side technology. This relates to workstation security more than designing a robust authentication/authorization mechanism. We can still implement some sort of extension authentication mechanism but it will be useless against someone who knows how to read extensions source code.

  2. There are basically two ways we can design the platform. Either by instrumenting the API to allow querying the authentication service. Or using token-based access, in which the API will request the presence of a valid token in every request it receives without being its emitter. This would mean extending the authentication service with a new role: API ticket issuer, which is rarely interesting. When reading the proposition, it seems we are merging both worlds by forwarding the session token to the API. This is wrong. First, this is not why the cookie-based session token was designed for. Second, it forces the API into implementing some sort of real-time synchronous link with the session management system of the user authentication service -> coupling that we can avoid easily.

  3. I will assume the main objective is to protect the API from unauthorized users and that we will not try to address threats relying on local system access.

  4. Now, considering we will not implement authentication logic in the API, we must rely on a model where users authenticate to the authentication service, thus enabling any underlying extensions to request an access token.

  5. This modifies the original scenario as follows:

    • The user logs into the website with the browser.
    • The website issues a cookie containing a session key.
    • The extension can now send a ticket request to the authentication service. Requests will include the session token (default browser behavior) and will therefore be authenticated.
    • Once the extension receives the ticket, the extension forwards it to the API and requests a session token.
    • The API validates the ticket by interrogating the session manager. If the session manager says "yes, I made this ticket and it is still valid", the API generates a session token and returns it to the extension. This token will inserted in all the subsequent requests, not the ticket. This will avoid any unnecessary workload on the session manager.
    • The token (do not confuse it with the ticket) can have a very short lifetime such as a few minutes -> if it expires, the extension just returns to the authentication service and asks for a new ticket (return to step 3 above).
  6. The above solution basically relies on how secure both the ticket and the token are. Their design must at least implement countermeasures against the following 5 remaining threats: i) attempts to guess the ticket/token (secure-enough random generation), ii) attempts to compute the ticket/token (large-enough entropy), iii) attempts to reuse the ticket/token (expiry), iv) attempts to tamper a valid ticket/token (integrity checking), v) attempts to access the API without a valid token/ticket (validating the token in each and every request the API receives).

  7. One additional advantage of this approach is that we can optimize resource allocation by emitting extension specific tokens, which in turn will trigger specific logic on the API (reduced API access, reduced lifetime, request throttling, etc..)

Hope it helps.

苍景流年 2024-11-16 19:41:55

因此,您在 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. 您可以跨域使用联合登录。这比代理方法更复杂,但您可以轻松找到适合您平台的现有实现。

So you have a website on example.com, and it needs access to api.com. Your extension assumes the user is logged in to example.com, extracts the session cookie and passes it to api.com to get an Oauth token. Sounds reasonable, but there are easier ways without having to write browser plugins.

In your case, api.com is going to communicate with example.com to verify the session cookie. There is a strong dependency between the two systems. OAuth is usually used where example.com and api.com do NOT trust each other.

Because the two systems already have some sort of trust in each other, you can do various things to simplify the architecture :

  1. You can create a proxy hosted on example.com/api/* that verifies the session and then blindly forwards to api.com/*. As far as the browser is concerned, there are no cross-domain requests, so everything works great.
  2. You can use federated login across domains. This is more complicated than the proxy method, but you can easily find an existing implementation for your platform.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文