Sunday, June 23, 2013

Responsible use of the ASP.NET MVC AntiForgeryToken

June 23, 2013 Posted by Jason Irwin , , No comments

The use of anti-forgery tokens is a necessary safeguard against cross-site request forgery attacks. The ASP.NET MVC framework provides easy-to-use security mechanisms right out of the box, but unfortunately these are opt-in rather than opt-out and are easy to miss/forget. For a non-trivial website it is difficult to guarantee tokens are supplied and checked in all form submissions and AJAX posts. This is how I do it.
Note: Web security is a tricky business and I do not consider myself a security expert. Use the information in this post at your own risk.

1. Use the ValidateJsonAntiForgeryToken attribute for AJAX calls

There's a nice post by Johan Driessen on anti-XSRF validation with newer versions of the .NET framework. I use Johan's ValidateJsonAntiForgeryToken attribute to great effect. In summary, Johan's attribute should be applied to actions invoked via AJAX calls. Check out his blog post - it explains everything in detail.

2. Ensure all AJAX posts contain a verification token

In my root layout file (master page) I use the following code to set expectations for jQuery AJAX calls. Prior to executing a call, the request verification token is read from the current page (Note: a Html.AntiForgeryToken call needs to be in place in every page which will utilize ajax posts) and passed into the request header. This saves me from needing to specify a token every time I create an AJAX call. (This can easily be modified to only send the token for desired HTTP verbs)
Loading ....

3. Ensure all POST methods have validation attributes applied

It's very easy to forget to apply the ValidateAntiForgeryToken attribute when developing new actions. I have a little unit test that I run to ensure that all post methods have either ValidateAntiForgeryToken or ValidateJsonAntiForgeryToken applied. The test fails and prints a list of offender actions when appropriate. This is a lifesaver when, inevitably, I'm developing some new functionality in a rush and haven't given security its appropriate consideration (hopefully this is a rarity).
Loading ....
Hopefully this saves somebody some time. Let me know if there are any considerations that I have missed, or if you know of a more elegant method of achieving the same!

Friday, June 21, 2013

Mocking NHibernate with Typemock Isolator is Awesome

June 21, 2013 Posted by Jason Irwin , No comments

Note: I am not affiliated in any way with Typemock

Unit testing methods that contain NHibernate calls is notoriously difficult. In fact, a common suggestion is to give up and use an in memory database instead. This is fine (I've personally tried it on multiple occasions), and it works I suppose, but has always felt more like integration testing than unit testing (what happened to "no external dependencies"?..perhaps I'm a purist) and undoubtedly slows down the test suite - especially in all but non trivial cases where reference data needs to be loaded.

I'm a novice Isolator user and messed around with the RecordExpectations syntax for a little bit before realizing just how simple Isolator makes things. Once you understand the warnings that Typemock puts out there, things get really easy. Really easy.

First Attempt
Let's say I wanted to fake the count of the products currently mapped to a specific category on my website. Normally the chained nature of NHibernate queryover calls requires mocking a LOT of stuff.

When you attempt to use Isolator's Isolate.WhenCalled method like in the case below, you may get an error message. Don't get despondent!

Code

 var session = Isolate.GetFake<ISession>(controller);

 Isolate.WhenCalled(()=>session.QueryOver<CategoryProduct>()
        .Where(x => x.Category == category && x.IsEnabled == true)
        .RowCount())
        .WillReturn(1);

Error Message
There is nothing better (or more rare) than getting a useful error message. In fairness, Typemock provides just that - not only highlighting the issue, but suggesting a fix too. Wonderful!

Test 'mytest' failed:
    TypeMock.ArrangeActAssert.NestedCallException : 
*** WhenCalled does not support using a method call as an argument.
-   To fix this pass null instead of Expression.Lambda()

***
* Example - this would work:
-   MyObj argument = Something.Other().GetStuff();
-   Isolate.WhenCalled(() => ObjUnderTest.MethodUnderTest(argument))...;
***
* Example - this would not work:
-   Isolate.WhenCalled(() => ObjUnderTest.MethodUnderTest(Something.Other().GetStuff()))...;
    at cx.a()
    at g4.a()
    at bh.a(Boolean A_0)
    at dl.b(Boolean A_0)
    at ij.b(Boolean A_0)
    at ij.a(Object A_0, Boolean A_1, Func`1 A_2, Action A_3, Action A_4, Action A_5, Boolean A_6)
    at ij.e(Object A_0)
    at TypeMock.ArrangeActAssert.ExpectationEngine`1.a(TResult A_0)

Updated Syntax
The issue here is that in the chained Where call I am using a lambda expression to filter my query. Since Typemock doesn't support methods being sent as arguments (and my lambda here is nothing more than an inline anonymous function) I need to break the lambda out into a standalone expression (Resharper is your friend).

What I end up with is the following terse (certainly compared to the alternative) syntax to mock a chained NHibernate call.

Expression<Func<CategoryProduct, bool>> expression = x => x => x.Category == category && x.IsEnabled == true;

Isolate.WhenCalled(()=>session.QueryOver<CategoryProduct>().Where(expression).RowCount()).WillReturn(1);

While Isolator is pretty pricey, it's this kind of power that separates it from the pack. I defy anyone to show me a better/easier way to do this.