6

We are in the process of creating a web service and have been investigating ways of securing it. In reality, the service is likely to get very little traffic and the data is likely to be of little use to anyone. However, we will need to authenticate users and do what we can to ensure the integrity of the data passed to the service.

Therefore, we've looked at using HMAC with the key being a 256 bit key derived from the users password entered on the client using PBKDF2. While I'm happy thus far with our implementation, I'm not sure how PBKDF2 with even 1000 iterations will perform on a iPhone/Android client. Also, as I mentioned earlier, it is unlikely anyone would want to compromise our service and while reading questions such as this one that mention things like "threat model and risk profile", I wonder if I am overdoing things.

The thing is, a third party has been commissioned to develop the client application, and their initial design doc provides some basic thinking of their idea of security and it is much more around something like;

MD5(shared secret + user password + request uri + timestamp + json serialised post data (if any))

Irrespective of whether we choose MD5, SHA1, or SHA256 is there any advantage to choosing HMAC/PBKDF2 over their suggested method (assuming roughly the same inputs to generate the hash)? Basically, am I overcomplicating this for a service that is likely to see a very small amount of traffic? At this stage, it is likely that all traffic will be over SSL also.

Mr Moose
  • 163
  • 1
  • 4

4 Answers4

8

Recommended approach. I recommend that you use SSL and authenticate the client using their password. Then you won't need any fancy MAC, hash, PBKDF2, etc.

Details. You asked how to authenticate the user. Here is a simple approach. Use SSL sitewide. When the user logs in (entering their password in via a web client), then set a session cookie that remembers the user for the rest of their session. (Make sure to use SSL throughout, and to set the secure flag on all cookies.) If you want, you can set a persistent secure cookie once the user authenticates, so they will never need to enter their password again on this browser.

If you want to access the web service from a dedicated mobile client, the same approach works fine. The web server can send a secure persistent cookie which the app can store permanently in its app-local storage, and can use that cookie to authenticate the client.

Alternatives. If for some reason the above is not possible, there are some fallback alternatives, but I think they are less preferable and more likely to have security problems. Here's one plausible fallback method:

  • On the first launch of your mobile client app, it prompts the user for their password, connects to the server over SSL, and sends the password over SSL. The server responds with a random 128-bit authentication key (chosen by the server using a crypto-strength PRNG).

  • The client app stores this auth key permanently in app-local storage. The server remembers the association between this auth key and the user's account permanently.

  • All future requests from the client app are authenticated using this auth key, as follows: you append a parameter to the end of the URL that holds the HMAC (under the auth key assigned to this client) of the rest of the URL, any POST data, and any other state that the server will taken into account.

As long as all requests are idempotent (e.g., for non-idempotent actions, you make sure to include a unique identifier somewhere in the URL parameters or in the POST data, and the server does replay detection), this should work OK to protect the authenticity and integrity of requests from the client to the server.

However, it has some security limitations. It does not protect confidentiality. It also does not protect other request headers, response data, and all sorts of other stuff. For this reason, it is not as secure as just using SSL. For instance, a site built using this approach likely will not be secure against man-in-the-middle attacks, due to the amount of other stuff that isn't protected by a HMAC, and thus won't be safe to use on an open Wifi network. For this reason, I suggest you just use SSL across the board and simplify your life, rather than trying to invent your own cryptographic request authentication format.

Security against password guessing. You'll note that none of my proposed approaches involve generating the cryptographic key as a function of the user's password. Users typically choose passwords. You should expect this will be especially true on mobile platforms, where entering passwords is a pain. For that reason, cryptographic keys derived from passwords will generally provide weak security and can often be broken by dictionary search. For instance, an eavesdropper who captures any one request will be able to mount a brute-force password search attack to recover the password and thus the crypto key, if the crypto key is derived from the password.

While PBKDF2 is an attempt to mitigate this as best as possible, the fundamental vulnerability remains. For this reason, I believe it is better to avoid using cryptographic keys that are derived from passwords, whereever possible. My solutions above are more robust in the face of weak user passwords, because they do not involve sending a password or anything derived as a function of the password in the clear over any connection.

The third-party design. You mention you hired a third party to come up with a design, and they proposed using something like MD5(secrets + data + more data). This is a bad idea. Don't do it. It has multiple cryptographic flaws. First, MD5(secret + data) is a poor message authentication code; it is susceptible to message extension attacks. Second, combining different kinds of data by concatenation is a bad idea and one of the top-ten most common crypto mistakes; both Amazon and Flickr had high-profile security flaws due to this. Instead, I recommend that you use a proper message authentication code (like HMAC), and that you use proper methods for concatenating the data fields that you want to authenticate, e.g., by including length fields.

D.W.
  • 98,420
  • 30
  • 267
  • 572
  • I'm just thinking about this for my own understanding. As I understand the above, the proposal is to use TLS/SSL, and send the password *with each request* using for example an HTTP Header inside the secure TLS channel? A common best practice is to use a 'computationally expensive' hash for storing the password. Then we would either have to **a)** accept the CPU load for password hashing on each request, **or b)** accept temporarily storing the passsword in plaintext (in fx Memcached) to allow fast (non-hashed) password verification server-side. Did I miss a better solution on the server side? –  Apr 09 '12 at 13:26
  • I'm no expert as you can see from my question. However, I certainly don't advocate sending the password with each request, but a hash that is only to generate using the users password. My dilemma is the 'computationally expensive' part you mention. I don't want to make the app secure, but run like a dog. For the most part, I'm happy with HMAC/PBKDF in my situation other than the time taken to generate the 256 bit key. I'm not sure this is going to be more than the round trip introduced by a challenge/response scenario. I'll need to see the effect of the solution on the client I guess. – Mr Moose Apr 09 '12 at 14:32
  • @JesperMortensen, thanks for your query. I've edited my answer to elaborate. Hopefully it addresses all of your questions. – D.W. Apr 10 '12 at 00:23
  • Thanks for your updates. It has certainly provided food for thought. Given we'll be using SSL for all communications, I feel that I probably have overdone things with HMAC/PBKDF2. I also feel that given I've only been looking at this for a week or so, I am probably doing things incorrectly and hence spending a lot of time building something that isn't actually as secure as it ought to be. The past week has certainly sparked my interest in this crypto techniques though, and I'll be reading the links more thoroughly. – Mr Moose Apr 10 '12 at 02:51
  • Just wanted to comment that you actually do want to derive encryption keys at least in part from the user password so that only the user possesses the key. Using PBKDF2 with HMAC (and a salt) will allow you to create a keyed hash that will better compensate for poor passwords. – Mark Burnett Apr 10 '12 at 07:52
  • @MarkBurnett, well, I disagree. I'll stand by the suggestions in my answer. I think it is better to use a randomly generated cryptographic key, and for your webservice to provide a way to get access to your crypto key once you prove you know the password (one crypto key per account), or to have the webservice generate a new crypto key that is linked to your account once you prove knowledge of the password (a separate crypto key per client, all linked to the same account). – D.W. Apr 10 '12 at 19:40
2

I working also on a webservice sessionless authentication. Check also amazon s3 auth.

They also do HMAC_SHA256 to "sign" the request with a timestamp.

But it's no strong over http (non ssl) because someone could sniff your request.

Amazon works agains that by only allow request with timestamp within +/- 15 min of the amazon server time.

Of course they also recommend to connect over http*s*.

  • Thanks. I've was just reading about this in the link provided in the first paragraph of [this answer](http://security.stackexchange.com/a/3330/8956). I'm not sure I totally follow the suggested approach sbown, but one thing that resonates with me in the article is the quote in the concluding paragraphs that states "...So yesterday's best practice might not be valid today.". This makes it all so difficult when I'm seeing so many varied opinions on what today's best practice is :) I think due to the trivial nature of this service, I'll likely opt for some easy to calculate MAC over HTTPS. – Mr Moose Apr 09 '12 at 14:18
1

Even if you here to use this system, you still need to use SSL.

Efficiency is really important for web services and your proposed authentication method is far from efficient or secure. The use of PBKDF2 would be a very poor choice because it would add significant CPU usage for each request and this would add significant lag as this check would have to be made before fulfilling the request.

The use of an HMAC introduces the possibility of an attack. md5 and sha1 both very broken primitives and should never be used in the context of security. (Although it should be noted that hash collisions do not affect HMACs, however hash functions have other problems). Even sha256+PBKDF2 can be cracked on a GPU or FPGA to retrieve your secret which makes this a very poor choice.

You should only use cryptography when there is no other option, you should never use it to introduce flaws into your system, and that is exactly what you are doing with this design. Another example of this flawed approach to session management is the .net oracle padding attack. Encrypting the session information doesn't guarantee that a user can't modify it.

If you want a secure system issue the client a cryptographic nonce. To do this I like using an entropy store like /dev/random. Then use this to retrieve information from a fast datastore like memcachd. Verification doesn't require an expensive hash function. This reduces the bandwidth overhead for each request compared to using an HMAC, and it cannot be tampered because there isn't a cryptographic primitive to break.

rook
  • 46,916
  • 10
  • 92
  • 181
  • I appreciate your comments, but I have a few questions for you. From what I've read over the past week or so, it seems that PBKDF2/HMAC are commonly used for authentication/message integrity. Are you saying that this is misleading? Actually, often articles I've read suggest using HMAC in conjunction with a nonce. [Signing requests in the flickr api](http://www.flickr.com/services/api/auth.oauth.html) is one. Also, are you aware of any good links describing the correct use of a nonce. I've not found any that are all that great thus far. Thanks again for your input. – Mr Moose Apr 09 '12 at 14:47
  • @Mr Moose Its the wrong tool for the job. And yes surprise surprise flickr built an insecure api, and i've collected tens of thousands of dollars from google as apart of their bug bounty program. All software has security problems. – rook Apr 09 '12 at 15:02
  • Can you elaborate on how HMAC can introduce the possibility of an attack? Especially in the case when it is used in conjunction with a nonce? I'm sure I'm missing something, but it seems to me that the use of a nonce with HMAC to both authenticate and ensure integrity of the request must be just as good (if not better) that just using a nonce on it's own. Again, if you've got any good references on the implementation of a nonce, then I'd appreciate seeing them. Thanks. – Mr Moose Apr 09 '12 at 15:16
  • @Rook, I'm not sure I'm following you. An HMAC, even if based on MD5 should be plenty sufficient here because it will (or at least should) be based on a nonce generated for a single request. Plus, since we are talking about hashing, not decryption, CBC-related padding attacks are not relevant. Further I don't think that 16 bytes would be a bandwidth issue and MD5-based HMAC is definitely not CPU intensive. – Mark Burnett Apr 10 '12 at 08:11
1

As others have said, it is not necessary to implement PBKDF2 on the client side if you are using SSL, but you may want to look into something like CHAP as a lighter-weight supplement to SSL and to address some of the potential vulnerabilities of SSL.

And by the way I think it is a great approach to first come up with how to overdo it, then work back to the more reasonable solution.

Mark Burnett
  • 2,810
  • 13
  • 16
  • Thanks for your comment. As I mentioned in another comment, this has certainly raised my interest in the crypto field in general. However, it has also raised more questions than it's answered. One of those being how to register new users along with their passwords through the service. That will be for another question, but it's timely as Jeff Atwood [had a great post] (http://www.codinghorror.com/blog/2012/04/speed-hashing.html) on that a couple of days ago. – Mr Moose Apr 10 '12 at 08:31
  • Yeah that is funny because I have seen so much effort put into hashing and session security, then they have a non-ssl signup form. – Mark Burnett Apr 10 '12 at 08:44
  • Another thing to do is to implement OpenID and let others worry about managing the passwords. – Mark Burnett Apr 10 '12 at 08:47