1

I spent a some time today looking through various HMAC implementations in C# for an upcoming WebAPI project. I wanted to start out with some existing code just to see it all work and understand it better before I either wrote it from scratch or modified it for my needs.

There are a bunch of great articles and posts both here and on the web. However, I have gotten to the point that I need some pointers and would greatly appreciate some insight.

I started with Cuong's post here: How to secure an ASP.NET Web API.

I knew I would have to expand upon it since I wanted to support both json and formencoded data. My test client is also written in C# using HttpClient and I spun up an empty WebAPI project and am using the ValuesController.

Below are my observations and questions:

  1. POSTing: In order to get Cuong's code to work (validate successfully), my POST needs to include the parameters in the URL, however in order to get the values to my controller, I need to include them in the body. Is this normal for this type of authentication? In this particular instance, the message I am hashing is http://:10300/api/values?param1=value1&param2=value2. Now I can parse the query string manually to get them, however in order to get the value to my controller through binding, I must also:

    var dict = new Dictionary<string, string>
                       {
                           {"param1", "value1"},
                           {"param2", "value2"}
                       };
    var content = new FormUrlEncodedContent(dict);
    
    var response = await httpClient.PostAsync(httpClient.BaseAddress, content);
    

Otherwise my parameter is always null in the post action of the ValuesController.

  1. I am planning on expanding the code to include a nonce. Between the combination of a nonce, a timestamp and the verb, is that enough for a secure hash? Is there really a need to also hash the message?

  2. I tried (very unsuccessfully) to extend the code to support json as well as form encoded data and I must be missing something obvious.

  3. Cuong is using the Authentication and Timestamp headers instead of putting the signature and timestamp in the query string. Is there a benefit to one method over the other? The majority of articles I have read have them in the query string itself.

The code looks great and I am a little out of my element here. I might be safer (saner?) just writing it from scratch to appreciate the nuances of it. That said, if anyone can lend some insight into what I am seeing that would be great.

At the end of the day, I want to be able to use the built in authorization mechinism of the WebAPI framework to simply attribute the methods/controllers, be able to accept form encoded and json data and reasonably model bind for complex types.

* Update *

I have done some more work today and below is the code from my nUnit PostTest. I figured out how to get the values through without both including them in the body and the query string (code below).

[Test]
    public async void PostTest()
    {
        using (var httpClient = new HttpClient())
        {
            var payload = new FormUrlEncodedContent(new Dictionary<string, string>
                       {
                           {"key1", "value1"},
                           {"key2", "value2"}
                       });

            var now = DateTime.UtcNow.ToString("U");
            httpClient.BaseAddress = new Uri(string.Format("http://ipv4.fiddler:10300/api/values"));
            httpClient.DefaultRequestHeaders.Add("Timestamp", now);
            httpClient.DefaultRequestHeaders.Add("Authentication", string.Format("test:{0}", BuildPostMessage(now, httpClient.BaseAddress, await payload.ReadAsStringAsync())));

            var response = await httpClient.PostAsync(httpClient.BaseAddress, payload);

            await response.Content.ReadAsStringAsync();

            Assert.AreEqual(true, response.IsSuccessStatusCode);

        }
    }

I also figured out the model binding portion of it. There is a great article here: http://www.west-wind.com/weblog/posts/2012/Mar/21/ASPNET-Web-API-and-Simple-Value-Parameters-from-POSTed-data that explains how POST works and I was able to get it to work with both a model of my own design as well as with the FormDataCollection object.

Now I am left wondering whether or not it is worth adding json encoded messages or if standardizing on FormUrlEncoding is the way to go. Also, are client nounce's enough or should I implement a server side nounce? Does a server side nounce double all of the calls to the service (first one throws a 401, second one includes the payload with the nounce?

Community
  • 1
  • 1
James Legan
  • 1,903
  • 2
  • 14
  • 21

0 Answers0