Wednesday, December 6, 2017

Secure ASP.NET Core Web API using API Key Authentication

I am implementing the simple web service that grants access via usual login and api login with some token. I have googled a bit for good solution but found it for asp.net mvc 5 application only (original article - Secure ASP.NET Web API using API Key Authentication – HMAC Authentication).

So it is something that helps me to do the same stuff for asp.net core that I am using for my web services.

First of all, I went through great workshop related to the various new pieces in ASP.NET Core Authorization - AspNetAuthorizationWorkshop. Also, check out the great article about Filters.

But both these materials are focused on Authorization, it is nice to know but for our purpose, we have to use Authentication.

I implemented custom AuthenticationHandler and override there HandleAuthenticateAsync. I returned AuthenticateResult.Success when request met requirment and AuthenticateResult.Fail in otherwise.

When handler was implemented I needed to configure service to use it. I wrote next code in Startup.ConfigureServices method:


And marked controller/action that I needed to protect:


Vu'a la, it works now.

PS: I used AddMvcCore() rather AddMvc() for better performance. Also, I added AddJsonFormatters for exploring JSON in respoce and AddAuthorization to use security.

You could find source there on GitHub.

EDIT:
My implementation had the bug; it related to the way how to request.body works. If the request.body was read already before during request pipeline, then it is empty when you try to read it the second time. AuthenticationHandler reads request.body for computing hash, so model binder can't process correct binding from request.body to post or put parameters. But this bug is easy to fix I have to enable rewind for body stream (Allow rewind request.EnableRewind(); and rewind request.Body.Position = 0;).

I have already updated sources code on GitHub.

5 comments:

Unknown said...

Hi,

Thank you for this article.

I have used your code it is working fine , however it is throwing an exception for Post and Put methods while model binding and it is sending a "400 (Bad Request)". If i remove the filter it is working fine. Please let me know if there is anything missing.

Regards,
Chakri

John said...

same issue i'm facing

RredCat said...

Guys were right, the code had the bug with post and put methods.
But it has been already fixed.

Unknown said...

Excellent approach, but it seems the Replay or ReplayAttack check is flawed, it needs to be thread safe and even MemoryCache has currently problems with multithreaded GetOrAdd

RredCat said...

You are right, it is exposed to replay attack. You have to improve key/headers with a date.
MemoryCache is used for prototyping only, you could replace it with a more reliable keys store.