9

I have designed a REST web service which requires authentication. It handles authentication in a manner similar to Amazon Web Services, namely: the user has an ACCESS_KEY (say, 'abcd') and a SECRET_KEY (say, 'aabbcc'). The SECRET_KEY is used to create a TOKEN: a SHA-1 using the request information, for example:

GET path HTTP/1.1
Date: Mon, 23 May 2005 22:38:34 GMT
ACCESS_KEY: abcd
TOKEN: SHA1(SECRET_KEY + ACCESS_KEY + Date + path)

I can check the TOKEN in the server and authenticate the request. Up to this point, I don't think there is anything wrong with the security model.

My only question, is how to provide the SECRET_KEY when using the service from a web page. I thought I could send it as a JavaScript variable (the connection is HTTPS) and simply use that variable in a JavaScript function that adds the appropriate header to every HTTPRequest. The initial authentication can be done using standard cookie-based approaches (for instance, relying on Django to handle a session).

So, the architecture looks like:

  • Web site session: handled by Django using standard session-based security (example.com)
  • The web site session receives via HTTPS the SECRET_KEY as a JavaScript global variable, which is used to add the appropriate headers to every HTTPRequest.
  • The HTTPRequests are made to api.example.com, which is oblivious to the Django session: it only cares about having the appropriate headers.

I believe this approach is secure, while maintaining a completely stateless REST API. I don't use standard HTTP authentication (basic or digest) because I don't want to hack the "you cannot logout" problem, and I want to keep the API strictly REST.

Do you have any comments regarding this approach? If it is flawed, how would you accomplish my goals?

Thank you!

AviD
  • 72,138
  • 22
  • 136
  • 218
Escualo
  • 191
  • 4
  • Hi @Arrieta, welcome to [security.se]! As several have alluded to, what is your threat model and risk profile? What assets are you protecting, from whom? And more simply: is SSL not an option? It really is the best -and simplest - solution for you. – AviD Sep 19 '11 at 21:55

3 Answers3

8

I dont see any flaws, but I do think you're overdoing it. It seems to me - I might be missing something - that you use a token because you think you should, not because there is a legitimate reason.

The best approach would be to first identify your (security) requirements and then look for the solutions.

One of the things you should think about with stateless API's is replay attacks. THe way you describe it, your protocol sounds like vulnerable to a replay attack. Moreover, it can be abused for CSRF since there is no randomness in each request. I'm not sure if this is something the REST API can fix, because it is an inherent webapp problem, but it's worth thinking about it.

Bottom line, nobody can assess if you're security is alright if you dont have security requirements (and a threat landscape).

Henri
  • 1,525
  • 10
  • 11
  • There is a legitimate reason to use the token; otherwise I cannot authenticate a user making an API request. For example, if I want to GET Bob's secrets, I go to http://api.example.com/secrets/bob/. How do you ensure that you are authorized to GET that resource? I do it via the headers, by checking that the user making the request is who he/she claims to be (and, of course, I have a database with a mapping user->permissions). Definitively, there is a window for a reply attack, but I can minimize it by providing strong keys and changing them frequently. I wish there was a universal solution! – Escualo Sep 19 '11 at 19:08
  • @Arrieta, please see the Wikipedia documentation on [replay attacks](http://en.wikipedia.org/wiki/Replay_attack). You don't necessarily need to change the main key frequently, and indeed that probably isn't adequate to protect against replays. Instead, use one of the solutions outlined there, such as nonces or timestamping (and expiring) requests. – Matthew Flaschen Sep 20 '11 at 01:34
  • @Arrieta, I see the authorization problem, but what is the added value of your token compared to username/password authentication? Your access key and secret key resembles to username + password. Please note that i'm _not_ saying its right or wrong :) – Henri Sep 22 '11 at 16:18
6

I think you should just stick with https. If major parts are generated in client-side javascript (e.g., the sha1 of the token), how difficult would it be for a MITM attack, where an attacker leads people to a faked version of your site, where the javascript is altered to reveal the secret key to the server? (E.g., alter the DNS and spoof the site on a public wifi hotspot.)

Also who's generating the date (client or server)? How long is a token valid? Is a token generated/validated two minute ago still valid? Could a MITM intercept a valid token to do a specific request and replay it (and do something malicious by replaying)?

dr jimbob
  • 38,768
  • 8
  • 92
  • 161
1

Can you please confirm that there following use case for your RESTful web service

  1. Other services/application sending request to your service. No need to maintain session state
  2. Request from browsers.

For the first use case, I think your approach is good. You can consider following changes to make it even better 1. Use SHA256 instead of SHA1 ( they say SHA1 is not considered too strong now a days) 2. Ensure that all secret key issued follow appropriate complexity rules

I hope you are only talking about the authentication model here and not other things. If you are talking about other things as well, SSL should be on your priority list ( for a number of reasons).

For second user case, the recommendations would differ depending on whether you want to really maintain a session state ( not really REST ;) ) or you ok with unrelated individual request from the browser

I can try to give a few suggestion based on what is the use case ( Session or no session)

Sachin Kumar
  • 820
  • 3
  • 9
  • 14
  • > 1. Use SHA256 instead of SHA1 ( they say it is SHA1 is not considered too strong now a days) Then "they" are wrong. Anyway: 1. I have no idea what you (= the OP) are trying to do. Why not use SSL for all requests, not just for the initial HTTPS request? If it is only an optimisation, it is premature. 2. Your TOKEN scheme is unsafe in some cases, there is a trivial attack. 3. It is not clear if you intent to use the Date header as an anti-replay feature. Please tell us more about the context, the tools you can/cannot use, the security requirements, the efficiency requirements, and also about – corrector Sep 22 '11 at 01:47
  • No "They" are not wrong, read this http://www.schneier.com/blog/archives/2005/02/sha1_broken.html I guess @Arrieta wants to know about authentication and not transport security ( and i guess two way ssl or certificate based authentication isn't really and option in his/her case) so SSL still being important isn't really an answer to his/her problem here – Sachin Kumar Sep 22 '11 at 04:22
  • Your link only showed SHA1 is only broken for [birthday attacks](http://en.wikipedia.org/wiki/Birthday_attack) - finding collisions in 2^69 ~ 5x10^20 (vs 2^80 ~ 1.2x10^24 as expected). However, I can't see how an attacker could use that to their advantage in this case: without knowing the secret key or SHA1 on the server side, you need to do a preimage attack (naively 2^160 ~ 10^48 - though likely the entropy in the secret key is much smaller) to guess an unknown hash, which should still be secure with SHA1. There's little harm using SHA256, so you might as well use it but its not a flaw. – dr jimbob Sep 22 '11 at 16:39