Secure OAuth in Javascript
Asked Answered
W

3

21

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.

Wieche answered 26/5, 2011 at 20:44 Comment(4)
Hm... seems to me that the extension method is inherently insecure, because your user could simply create their own extension or other method of accessing the api.Karb
But they would still need to authenticate with the website. If they can get a Cookie from the site, they can access the site anyway. So my method would only be as insecure as a website login.Wieche
How about storing OAuth tokens in LocalStorage? LocalStorage can only be read by the client browser and isn't send in HTTP request headers.Corunna
But the issue here isn't storing the tokens themselves. It's authenticating with the api to get the OAuth tokens.Wieche
C
8

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.

Corunna answered 9/6, 2011 at 15:53 Comment(2)
While this is an excellent answer, it does not address my question. My question is whether my method of distributing tokens is a secure one. It does not pertain to storing them. It's a server-side, rather than a client-side issue.Wieche
You have to weigh Security vs. Usability. In my case, usability won over security somewhat when it comes to generation Consumer/Request/Access Tokens.Corunna
P
3

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.

Perspicuous answered 7/2, 2012 at 0:45 Comment(0)
G
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.
Golter answered 9/6, 2011 at 20:25 Comment(1)
Unless I'm missing something, you can't do client side auth with OAuth 1.0 because you can't expose the consumer secret on the client side. Therefore, the proxy solution sounds like the way to go. I'm new to OAuth though, so could be missing something. Some info: quora.com/Is-it-safe-to-implement-OAuth-on-the-client-sideVolgograd

© 2022 - 2024 — McMap. All rights reserved.