Sunday, August 26, 2012

ASP.Net Web API Error Handling, HTTP Status Codes, and You

This is really 502 - Bad Gateway
I'm pretty sure it's not the cat's fault.

EDIT: I actually recommend against a lot of what I'm saying here now. Web API endpoints shoudl always be returning HttpResponseMessage, and those messages could always be created by Request.CreateResponse();  I'll write more on this later.

So it seems to me that not a lot of people have figured out what they should be doing when they want to throw an error from their Web API, but give something back to the client that contains some sort of information about what happened. If you're here you might be here because you've realized that simple throwing any old exception from your Web API results in a "500: Internal Server Error" with exactly nothing in the body of the response that might explain to the client what went wrong.

There are a few things at play here. The quick and dirty version is you're probably throwing the wrong type of exception, and returning the wrong type of status code. Let me explain:

You need to be throwing HttpResponseException

When you throw just any old error, ASP.Net interprets that as an error in the operation of your web application. In other words, it thinks (and rightfully so) that you've experienced an "internal server error". As such, it just sends out a 500 error. You might think, "Well great, but why doesn't it send out the message in my exception? Why can't they do that for me? Shouldn't that be done for me?" Well, actually no, you don't want to send an explanation with a 500 error, but I'll get to that.

If you throw an HttpResponseException, ASP.Net knows that you're attempting to throw an error that you'd like to communicate back to the client with specific information. This, however, does not mean that you should use a 500 error, or that there were all of a sudden be a body in with that 500 error. Because there shouldn't be.

You should be returning 4XX errors, not 5XX errors

The reason the developers of this technology opted not to send the contents of your exception out with a 500 error is because 5XX errors are meant to be sent out as a notification that an error occurred on the server, and there's nothing the client can do about it. Think of it like that annoying "engine maintenance" light on the dashboard of your car, if you're getting that, just pounding on the gas harder isn't likely to do anything to fix the issue. It's an internal issue.

400 errors are your friends. 4XX errors are there to state that an error occurred and there's something the client can do about it. There is a whole list of them, but the two you'll probably need the most are 404 and 400. 404 everyone knows... "not found". This can be returned when content isn't found. For example if a user queries from some widget by id, and the id is invalid... your app didn't find it, so 404.  400 is for a bad request. That means the server got the request okay, but there was something wrong with it and it shouldn't b e resent unless something about it changes. (I'm sure somewhere the authors of RFC 2616 want to slit their wrists after reading my grotesque butchery of their words).

For a more complete list read the definitions yourself. Just be sure to actually read the definitions, some of them have rather generic sounding names but very specific meanings. For example, "406 - Not Acceptable" which actually means that the type requested in the Accept header isn't something the server can return, so if the client requested "text/fibbertyjibbets" rather than "application/json" they're S.O.L. and they're going to get a 406. Anyhow, the point is, read the definitions before you use them. Odds are, most of the time, 400 and 404 will do.

So 4XX errors will actually return a reason along with them, as well as a body that offers some explanation. This is way better than a 500: Internal Server Error with no explanation. And it's also the more correct response.

But how to do this in ASP.Net Web API?

Since ASP.Net Web API can return a variety of content types: XML and JSON for example, I think the most appropriate thing to do is return a very simple string with the basic reason in it. It can be interpreted easily by any client, and it's simple to implement.

What I did was add the following methods to my custom ApiController base class. Then when I needed to use them, I basically call: throw Conflict("Invalid somethingerother"); or throw NotFound("Record not found"); This does everything I need it to do to return something valid to the client.

/// <summary>
/// creates an <see cref="HttpResponseException"/> with a response code of 400
/// and places the reason in the reason header and the body.
/// </summary>
/// <param name="reason">Explanation text for the client.</param>
/// <returns>A new HttpResponseException</returns>
protected HttpResponseException BadRequest(string reason)
    return CreateHttpResponseException(reason, HttpStatusCode.BadRequest);

/// <summary>
/// creates an <see cref="HttpResponseException"/> with a response code of 404
/// and places the reason in the reason header and the body.
/// </summary>
/// <param name="reason">Explanation text for the client.</param>
/// <returns>A new HttpResponseException</returns>
protected HttpResponseException NotFound(string reason)
    return CreateHttpResponseException(reason, HttpStatusCode.NotFound);

/// <summary>
/// Creates an <see cref="HttpResponseException"/> to be thrown by the api.
/// </summary>
/// <param name="reason">Explanation text, also added to the body.</param>
/// <param name="code">The HTTP status code.</param>
/// <returns>A new <see cref="HttpResponseException"/></returns>
private static HttpResponseException CreateHttpResponseException(string reason, HttpStatusCode code)
    var response = new HttpResponseMessage
            StatusCode = code,
            ReasonPhrase = reason,
            Content = new StringContent(reason)
    throw new HttpResponseException(response);

Here's an example of one of the above methods in use:

public Widget GetById(int id) 
    using(var context = new MyDataContext()) 
        var widget = context.Widgets.FirstOrDefault(x.Id == id);
        //if we don't have the widget, throw our HTTP error.
        if(widget == null) throw NotFound("Could not find widget: " + id);
        return widget;

You can of course implement this same basic idea however you like, but the principle would remain the same. It's good to have a better understanding of HTTP status codes and what they mean, and it's good to use them appropriately.

What you DO NOT want to do

You do not want to return the guts of a whole Exception object in the body of your error response. You don't need to, or want to be sending the whole stack trace and other sensitive information to any old client that makes a bad request. It's just not a good idea. Stack traces and other such things should be recorded for you by a good logging solution, and they should never, ever be returned to clients. Particularly unknown clients.

You do not want to return the wrong HTTP status codes. Will it break anything? Probably not. Will it make you look like a chump that didn't read the RFC before you used the code? Yes. Don't do it. Don't be a chump.

EDIT: I've changed this slightly. It was really late and I was tired when I was writing this. I meant 400 error, not 409. 409 is when you have a state conflict. Like for example a double submit of some data, or data in an unexpected state that is causing an issue. It's could be valid for nearly any error I suppose, but it seems a little more specific tied to the state of some data than 400.

Wednesday, August 22, 2012

Just Salting And Hashing Your Passwords Isn't Enough

I was tempted to reference that Angelina Jolie movie here... But I resisted.

I won't go over this in too much detail, because that's already been done by many a development blog, but the basics are:

  • Never store plain text passwords, store hashes. Storing plain text passwords is a cardinal sin, when a hacker gets ahold of this (assume the worst), they'll have a list of emails and favorite passwords. This is gold to them. They'll get into gmail accounts, and from there it's all over.
  • Require some level of complexity to your passwords. Weak passwords are easier to brute force... duh. Enforce a policy that ensures a high level of entropy.
  • Salt your passwords prior to hashing. Add something special to each password so it's harder to figure out what it was based off of the hash. A good size salt will also eliminate the effectiveness of rainbow tables.
  • ...With a random salt. Even better, everyone gets their own salt. Salt for everybody!
  • Make it slow on purpose. This one might seem odd to some people. It's a really good idea to make sure your hashing algorithm is good and slow. This is because if it's too quick it makes it easier to brute force. 

Something to know: This security needs to be updated as hardware gets faster. Basically has hardware gets faster, you might want to add iterations to your PBKDF2 step. This is because you'll want to keep the time to compute the hash high enough it's not easily brute forced by current hardware. 200-400 ms on top notch hardware should be more than enough to slow down a brute force attack to the point where it's not feasible.

Microsoft .NET has a built-in implementation of PBKDF2 for iterative stretched key generation and HMAC SHA512 for keyed hash creation. The following code demonstrates such an implementation. I think it's pretty self explanatory, but if not here's the play by play:

  1. Get a salt using RNGCryptoServiceProvider. This is just a cryptographically secure random number generator.
  2. Use PBKDF2  (Rfc2898DerivedBytes) to get a key from the salt and the text over many iterations.
  3. Hash the text with HMACSHA512 using the key and the salt.

A test harness for the Hasher class

The Hasher class

Wednesday, August 15, 2012

Creating A Digitally Signed Security Token For A REST API

Recently I was tasked with securing a Web API. I wanted to use token authentication that didn't require that I look up a user id from that token for every request. In order to do this, I knew I'd have to embed the user id and possibly some other data in the token string and make it tamper-proof (esque).

My solution was to use RSA digital signing to sign a my token string to ensure it hasn't been tampered with. Then I'd have to send the signature as part of the token string in order to have something to check on the other end. Digital signing with RSA uses the private key to sign some data, and then the public key (or private key, if in a safe environment) to verify the signature.

EDIT: I wanted to express the advantage of having a public key, because I didn't really say anything about that in my initial post: A big advantage to using an asymmetric algorithm to do the digital signing is the fact that you can share a public key. If you have third party applications consuming your API, you can assign each of them a key pair, storing their private key yourself and giving them the public key. They can then use the public key to verify your tokens independently without making a call to your API for any reason.

There are a few drawbacks to doing things this way rather than some sort of token where you're looking up the token in a database:

  • The biggest drawback is you're limited in the amount of information that can be attached to your token without making your token huge. How big is too big? Well, that's up to you, really. But I like to keep mine under 200-300 characters or so, depending on how I'm sending it back and forth.
  • The other drawback is you must expire these types of tokens, since there is no way to manually expire tokens like this from the server side. Otherwise once you issue the token, it's good forever until you change your private key.

What follows is a simplified version of my solution. What I did was a bit different, as I did some custom binary serialization to reduce the size of my token string, but overall this is the general idea: