gdubs
gdubs

Reputation: 2754

HMAC and WCF Service .net

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!

Upvotes: 2

Views: 2239

Answers (2)

Despertar
Despertar

Reputation: 22382

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

Upvotes: 4

joocer
joocer

Reputation: 1121

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.

Upvotes: 0

Related Questions