2

So I'm very new with HMAC authentication and I really don't know what I'm doing nor reading atm.

I've been trying to understand the following articles / links / discussions properly:

How to implement HMAC Authentication in a RESTful WCF API

http://blogs.microsoft.co.il/blogs/itai/archive/2009/02/22/how-to-implement-hmac-authentication-on-a-restful-wcf-service.aspx

http://buchananweb.co.uk/security01.aspx

With that said I have a few questions:

  1. Understanding the first link, if for example I have a loginAuthentication service created in .net and will be accessed from an iPhone app do I pass an unencrypted username (message) for this and should return just a true / false or should it return an encrypted string in which I will be using later on for other transactions (Delete, Insert services, etc)?

    [ServiceContract]
    
    public partial class LoginService
    {
    
     [OperationContract]
     bool Authenticate(string username) {
       // stuffs
     }
    

    }

  2. With that said, after I verified the user, and this is where I get lost. Is it better that I save something in the database 'with a timestamp' (someone told me about this and I read some discussions about this too)? Or do I just return it with the encrypted message (dependent on the first question) so that everytime a request is made the timestamp is already attached?

    a. And what do I do with that timestamp?

    b. Is it going to be used once the message is sent again for another transaction?

  3. Keys and secret message. The way I understood it is that the key will be the password of the user. So if the user sends his username I can open the message using the password of that user? This makes sense if the user already has a session and is just requesting to get data or requesting for a delete, insert, etc. Should it still be the same way if it's just authenticating the username and password of the user?

Thank you for your time!

Community
  • 1
  • 1
gdubs
  • 2,724
  • 9
  • 55
  • 102

2 Answers2

4

The first thing I would like to mention is that the WCF Web Api was a beta project which is no longer being developed. It was replaced by ASP.NET Web API which is an awesome framework for developing RESTful services.

If you want to get a good idea how a RESTful service and authentication works the Netflix API would be a great place to start. They have a lot of documentation regarding the security portion and this helped me understand HMAC a lot more.

HMAC creates a hash using a secret key. The client and server both maintain a copy of the secret key so that they can generate matching hashes. This allows you to 'sign' a request which serves as both authentication (you know the person sending it is who they say they are), and message integrity (knowing the message they sent is the original message and has not been tampered with).

A signature is created by combining

1. Timestamp (unix epoc is the easiest to send in urls)
2. Nonce (a random number that can never be used twice to protect against someone re-using it)
3. Message (for a GET request this would be the URL, a POST would be the whole body)
4. Signature (the three previous items combined and hashed using the secret key)

Each of the above can be sent in the query string of the request, then the server can use the first 3 and their copy of the secret key to recreate the signature. If the signatures match then all is good.

In a RESTful API that is over plain HTTP (not using HTTPS over an ssl), I would sign every request sent because again this authenticates and provides message integrity. Otherwise if you just send an authentication token you know the user is authenticated but how do you know the message was not tampered with if you do not have a Message Digest (the HMAC hash) to compare with?

An easy way to implement the server-side checking of the signature is to override OnAuthorization for System.Web.Http.AuthorizeAttribute (Make sure not to use Mvc autorize attribute). Have it rebuild the signature just as you did on the client side using their secret key, and if it does not match you can return a 401. Then you can decorate all controllers that require authentication with your new authorize attribute.

Hopefully this helps clear up some of your confusion and does not muddy the water even further. I can provide some more concrete examples later if you need.

References:

Netflix Api Docs: http://developer.netflix.com/docs/Security#0_18325 (go down to the part about creating signatures, they also have a link which shows a full .NET example for creating the HMAC signature)

.NET class for creating HMAC signatures http://oauth.googlecode.com/svn/code/csharp/OAuthBase.cs

Netflix API Wrapper I wrote: https://bitbucket.org/despertar1318/netflix-api/overview

ASP.NET Web API: http://www.asp.net/web-api

Despertar
  • 21,627
  • 11
  • 81
  • 79
  • Thanks for the reply! That actually made things a little clearer. Altho, I still have a few questions. Since I'm really new with this,and trying it out stepbystep,let me start with login authentication first with an iphone app that calls a login webservice.I send the username and a hashed pword.I return if it's true or false (authenticated), if it's true I save the username and password (this will be my shared key).Now if i do a get transaction after log in,let's say "/GetAppointmentDetails?apptid=1".How do i know if the requester is allowed to see the appt details? i pass the {username}..? – gdubs Nov 29 '12 at 20:42
  • alongwith a key to verify if he's the right person and is allowed to see the appointment details? Or do I hmac hash the whole URL parameters resulting to "/GetAppointmentDetails?hmac=kjsodjdkie...." and compare that hmac token/hashed string to the database? Gahhh, really confused. – gdubs Nov 29 '12 at 20:44
  • Ok,so after reading the netflix API,i have a better idea now.But,my problem is the nonce part,so let's say that i send my username and pword,it returns true(with a nonce?),i save the pword for key,now i request a transaction "appointment",i will send back the "nonce" that i got on login? and return a new "nonce" with this request to be used on the next one. am i still on the right track? – gdubs Nov 30 '12 at 03:39
  • 1
    Nonce stands for 'Number used Once". So you never want to send the same nonce twice. It can actually be an incremented number, random letters/numbers, or I usually like to use GUID's since they are designed to be unique and easy to create, Guid.NewGuid.ToString(). On the server side it could be as simple as a .txt file with each nonce that has been used, if you are already using a database you could have a table full of nonces. Then each time you verify a request you just make sure the nonce they provided has not already been used, otherwise it could be someone trying to replay a previous msg. – Despertar Nov 30 '12 at 08:25
  • 1
    If you do not want to sign each request with a timestamp, nonce, and hmac hash, but would rather go with a authenticate once approach I would suggest using Forms Authentication. This was originally used with the original asp.net webforms, but it can actually work quite well in many other scenarios. How it works is that you make a call to the Authentication service and the if the correct credentials are supplied you create an encrypted Authentication token which is then passed back in a cookie. Now each time that user sends another request, say to /GetAptDetails, that token is passed as well. – Despertar Nov 30 '12 at 08:29
  • 1
    And ASP.NET will handle all the authentication details on your behalf. You can specify how long the token is good for and even store the username in it so you can always identify the user with subsequent requests (perhaps different users will have access to different areas of the api depending on groups or permissions). http://msdn.microsoft.com/en-us/library/ff647070.aspx . If you do not want to use cookies there should be a cookieless version as well where the auth token is passed in query string instead. – Despertar Nov 30 '12 at 08:31
  • Ok now that makes sense. I was trying to figure out how the verification of the nonce will work if it's only used once.So I save it on the dbase alongwith the timestamp?Or is it best to just do a compare on the timestamp while doing the transaction to the current system date?Now going back to the Netflix API,why do they require you to give a consumer_key,im guessing it's just another layer of security for accessing their client's data and wouldn't be too releveant for me...Thanks so much,this is helping me a lot btw. – gdubs Nov 30 '12 at 14:44
  • 1
    The consumer_key would be the equivalent of a username, except it does not need to be something easy to recognize. Each user is given one consumer_key with a consumer_secret. Since the secret is never sent in plain text and always hashed along with the other info, you would need to use the consumer_key to look up their copy of the consumer_secret so they can create an equivalent hmac hash. This allows you to not only know they are authenticated, but since you know 'who' they are you can then provide authorization for different levels of your api. – Despertar Nov 30 '12 at 19:26
  • Good to know! Thanks for the quick reply. For the nonce tho,won't the database get too big specially if every transaction will have a nonce? Also if the mobile app will send requests about 400 - 500 times a day?Or should i clear out the table (nonce) after a period of time?Also, thanks for your Netflix project link! – gdubs Nov 30 '12 at 21:36
  • 1
    If the timestamp is only good for say 10 minutes then technically you could clear your nonces every 10 minutes because if someone tried to reuse one of those nonces the timestamp would be expired and invalidate it. – Despertar Nov 30 '12 at 22:15
  • Is there any other way to check the requests without using nonces? A little worried about performance hits when I have to check nonces and delete them. Or I shouldn't be worried about that at all? – gdubs Dec 03 '12 at 15:16
  • 1
    Without the nonce, you are leaving a window open for the length the timestamp is valid. Say you send a request to update a resource. With a nonce if someone captured that request and re-sent it they would get access denied because the nonce has already been used. Without a nonce and say a timestamp that is good for 10 minutes, someone could re-issue that request within the 10 minutes before the timestamp expires and the signature will be valid. It's up to you how important the data is that you are protecting and how bad it would be if a third-party could re-issue a request. – Despertar Dec 04 '12 at 00:50
  • ok so i think i'm kinda understanding this now. The nonce is basically generated by the client and then sent to the api,the api then checks if the nonce has been requested already from the dtabase,if not then ok and then save to keep record for the next 10 min.else return an error. Is my understanding correct? – gdubs Dec 04 '12 at 05:02
0

Looking at your questions in turn

...do I pass an unencrypted username (message) for this and should return just a true / false or should it return an encrypted string in which I will be using later on for other transactions (Delete, Insert services, etc)?

If you just returned a boolean, you'd have no way to then match the authentication request to subsequent requests. You'll need to return some sort of authentication indicator, on a classic website this would be the session cookie, in your instance you want to pass a value that will act as shared key.

Is it better that I save something in the database 'with a timestamp'? Or do I just return it with the encrypted message so that everytime a request is made the timestamp is already attached?

Back to the session analogy, you want to store the key from question one somewhere (the database?) with a timestamp that indicates the life of the session/validity of the key. If it's forever then I wouldn't bother with the timestamp, if it's anything else you'll need something to say when it expires.

The way I understood it is that the key will be the password of the user. So if the user sends his username I can open the message using the password of that user? This makes sense if the user already has a session and is just requesting to get data or requesting for a delete, insert, etc. Should it still be the same way if it's just authenticating the username and password of the user?

This is where the HMACing happens. You have your shared secret, you have a message, this is how I usually combine it all together.

Use all of the message as the body of data to be hashed (that way you can be sure that someone's not just copied the hash and part of the message). Hash the body of the message using the key we shared in step one. You could salt this if wanted, I'd use the username.

Finally make sure the message contains a timestamp (UTC preferably), this way you can help prevent replaying the message later. The service that's responding to the message can compare the timestamp to what it thinks the time is. If it falls outside given bounds, fail the message. Because the timestamp will be part of the HMAC, someone can't just update the date and replay the message, the hashes won't match as soon as the message is tampered with.

joocer
  • 1,111
  • 1
  • 7
  • 11