Sunday, January 18, 2015

Enhance your Web API 2 project's security using the Microsoft AntiXssEncoder

It's fairly straight-forward to add anti-XSS security to your Web API 2 project.  You might be wondering why you would though.  Out of the box, Web API 2 does not automatically encode and decode for you.

There is a potential problem in that the web API project could be receiving untrusted input from a HTML5 and JavaScript client.  If that input gets persisted, or displayed elsewhere, and then displayed later you could have persistant XSS on your hands.

The solution is fairly simple though believe it or not.

1) Nuget packages can be installed for use with the Web API project's models
 <package id="ASPNetWebAPIAntiXss" version="1.0.0" targetFramework="net45" />
  <package id="ASPNetWebAPIRequestValidator" version="1.0.0" targetFramework="net45" />

2) An attribute can be added to the models for the first package above (uses the AntiXssEncoder under the covers)
Add this to models:
[AntiXss]

3) Next you need to secure data coming in via query string or posts other than models (query string data example here)

For Web.config:

<httpRuntime encoderType="System.Web.Security.AntiXss.AntiXssEncoder" />


==================

For WebApiConfig.cs (in Register)

            RequestValidator.Create<ValidationError>()
                .MapPropertyName(x => x.Property)
                .FlattenErrorMessages()
                .Map(x => x.Message).ToErrorMessage()
                .Init(config);

==================
Then create a class that extends ActionFilterAttribute and in OnActionExecuting add the following
            // Check query string data for XSS using Microsoft's AntiXssEncoder
            var queryStringDataForRequest = actionContext.Request.GetQueryNameValuePairs();

            if (QueryDataContainsXss(queryStringDataForRequest))
            {
                var response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, 
                    new HttpResponseException(new HttpResponseMessage()));
                actionContext.Response = response;
            }

It's up to you to define QueryDataContainsXss().  The simplest, and perhaps safest implementation is to compare the input to encoded input using the AntiXssEncoder with default settings.  If you find that they are not equal then break and return false.

Then you can add the attribute to the controllers.
Add this to controllers:
[AntiXssActionFilter]

It's a good idea to add tests for your implementation too.  RestSharp is an easy way to add REST client abilities to your tests.  I hope that this is helpful to others.  Cheers.

Kristian

Tuesday, November 25, 2014

Mocking controller context and route data for Web API controller (OAuth attribute)

ASP.NET Web API 2 is a great technology for creating RESTful web services.

However, there can be a challenge for unit testing if you need to mock the OAuth "Authorize" attribute on a controller's method.

This is where Moq comes in.  It's available here - https://github.com/Moq/moq4 .

So, say if you have a controller method that uses the OAuth "Authorization" attribute and it needs unit test coverage then you can use Moq to setup your test.

Example psuedocode for controller method:

[OAuthAuthorization]
public CustomData GetCoolData()
{
    // get data from route here
    // more business logic
    return CustomData object;
}

--------------

Example helper for setting up controller context and route data:
public HttpControllerContext SetupControllerContext(ApiController controller)
{
    controller.ControllerContext = // new one up here or call another helper to populate object
    controller.ControllerContext.Request = new HttpRequestMessage();
    controller.ControllerContext.Request.Headers.Add("Authorization", "Bearer fakeToken");
    controller.ControllerContext.RouteData = new HttpRouteData(new HttpRoute());
    // Add any key value pairs to route data here
    controller.ControllerContext.RouteData.Values.Add("key", valueObject);

    return controller.ControllerContext;
}


Example test code snippet:

// Arrange
_controller.ControllerContext = SetupControllerContext(_controller);
// Setup mock here to mock the data provider and return what you'd like or throw if negative test

// Act
var result = _controller.GetCoolData();

// Assert
Assert.IsNotNull(result);
// do any further validation

That's pretty much it.  There wasn't much online about how to do this so I wanted to share.  Cheers.