Search code examples
asp.netwcfwcf-data-serviceswcf-securityhmac

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!


Solution

  • 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