Tag Archives: csrf

Protecting ASP.NET Applications Against CSRF Attacks

Fork me on GitHub

ARMOR

ARMOR

For a brief overview of the Encrypted Token Pattern, please refer to this post.

Overview

The Encrypted Token Pattern is a defence mechanism against Cross Site Request Forgery (CSRF) attacks, and is an alternative to its sister-patterns; Synchroniser Token, and Double Submit Cookie.

Each of these patterns have the same objective:

  1. To ensure that any given HTTP request originated from a trustworthy source
  2. To uniquely identify the user that issued the HTTP request

In the first instance, the need to ensure that requests originate from a trustworthy source is an obvious requirement. Essentially, we need to guarantee that any given request has originated not only from the user’s web-browser, but also from a non-malicious link, or connection.

Why the Encrypted Token Pattern?

A Simple CSRF Attack

Consider a banking application. Suppose that the application exposes an API that allows the transfer of funds between accounts as follows:

http://mybank.com/myUserId/fromAccount/toAccount/amount

Web browsers share state, in terms of cookies, across tabs. Imagine a user that is logged into mybank.com. They open a new tab in their internet browser and navigate to a website that contains a link to the above URI. An attacker that knows the user’s bank account number could potentially transfer any given sum from the user’s account to their own. Remember that the user is already logged in to mybank.com at this point, and have an established session on the web-server, if not a persistent cookie in their web-browser. The browser simply opens a new tab, leverages the user’s logged in credentials, and executes the HTTP request on the user’s behalf.

How to Defend Against CSRF Attacks

In order to defend against such attacks, we need to introduce a token on the user’s behalf, and validate that token on the web server during HTTP requests, ensuring that each request

  • Originates from a trusted source
  • Uniquely identifies the user

Why uniquely identify the user? Consider that CSRF attacks can potentially originate from valid users.

A More Sophisticated CSRF Attack

John and David are both valid users of mybank.com. John decides to post a malicious link. This time, the attacks is more sophisticated. John has built a small web server that issues a HTTP request to the mybank.com money-transfer API:

http://mybank.com/myUserId/fromAccount/toAccount/amount

This time, John has supplied a valid token – his own (remember, John is also a valid user). Now, assuming that mybank.com does not validate the identity of the user in the supplied token, it will determine the request to have originated from a trusted source, and allow the transfer to take place.

The Encrypted Token Pattern

The Encrypted Token Patterns protects web applications against CSRF attacks by generating a secure token at server level, and issuing the token to the client. The token itself is essentially a JSON Web Token (JWT) composed of a unique User ID, randomly generated number (nonce), and timestamp. Given that the token is a JSON object, it is possible to include any additional metadata in the token. The process flow is as follows:

Encrypted Token Pattern

Encrypted Token Pattern (click to enlarge)

Leveraging the Encrypted Token Pattern

The Advanced Resilient Mode of Recognition (ARMOR) is a C# implementation of the Encrypted Token Pattern, available on GitHub under the MIT license that provides a means of protecting ASP.NET applications from CSRF attacks, by leveraging the Encrypted Token Pattern. The following steps describes a typical setup configuration.

ARMOR

ARMOR is a framework composed of interconnecting components exposed through custom DelegatingHandler and AuthorizationAttribute classes. ARMOR is essentially an advanced encryption and hashing mechanism, leveraging the Rijndael encryption standard, and SHA256 hashing by default, though these are concrete implementations; ARMOR provides abstractions in terms of encryption, allowing developers to leverage custom concrete implementations. ARMOR has two primary directives:

  • To generate secure ARMOR tokens
  • To validate secure ARMOR tokens

ARMOR Web Framework

The ARMOR Web Framework is a set of components that leverage ARMOR itself, allowing developers to leverage the ARMOR framework in a plug-and-play fashion, without necessarily grappling with the underlying complexities of encryption and hashing. This tutorial focuses on leveraging the ARMOR Web Framework in C# to protect your ASP.NET applications from CSRF attacks.

Leveraging ARMOR in ASP.NET

ARMOR Web Framework Package

Download the ARMOR Web Framework package from Nuget:

PM> Install-Package Daishi.Armor.WebFramework

Apply Configuration Settings

Add the following configuration settings to your web.config file:

<add key=“IsArmed” value=“true” />
<add key=“ArmorEncryptionKey” value=“{Encryption Key}” />
<add key=“ArmorHashKey” value=“{Hashing Key}” />
<add key=“ArmorTimeout” value=“1200000” />

IsArmed

A toggle feature easily allowing developers to turn ARMOR on or off

ArmorEncryptionKey

The encryption key that ARMOR will use to both encrypt and decrypt ARMOR tokens

ArmorHashKey

The hashing key that ARMOR will use to generate and validate hashes contained within ARMOR tokens. ARMOR implements hashes as a means of determining whether or not tokens have been tampered with, and to add an extended level of entropy to token metadata, rendering them more difficult to hijack.

ArmorTimeout

The time in milliseconds that ARMOR Tokens remain valid.

In order to facilitate encryption and hashing, ARMOR requires two keys. You can generate both keys as follows:

byte[] encryptionKey = new byte[32];
byte[] hashingKey = new byte[32];

using (var provider = new RNGCryptoServiceProvider()) {
    provider.GetBytes(encryptionKey);
    provider.GetBytes(hashingKey);
}

These keys must be stored in the ArmorEncryptionKey and ArmorHashKey values in your configuration file, in Base64-format.

Hook the ARMOR Filter to your application

Core Components

Authorization Filter

The Authorization filter reads the ARMOR Token from the HttpRequest Header and validates it against the currently logged in user. Users can be authenticated in any fashion; ARMOR assumes that your user’s Claims are loaded into the current Thread at the point of validation.

The following classes facilitate authorization for both MVC and Web API projects respectively:

  • MvcArmorAuthorizeAttribute
  • WebApiArmorAuthorizeAttribute

 Fortification Filter

The Fortification filter refreshes and re-issues new ARMOR tokens. The following classes facilitate fortification for both MVC and Web API projects respectively:

  • MvcArmorFortifyFilter
  • WebApiArmorFortifyFilter

Generally speaking, it’s ideal that you refresh the incoming ARMOR token for every HTTP request, whether that request validates the Token or not; particularly for GET HTTP requests. Otherwise, the Token may expire unless the user issues a POST, PUT, or DELETE request within the Token’s lifetime.

To do this, simple register the appropriate ARMOR Fortification mechanism in your MVC application,

public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
    filters.Add(new MvcArmorFortifyFilter());
}

or in your Web API application:

config.Filters.Add(new WebApiArmorFortifyFilter());

Now, each HttpResponse issued by your application will contain a custom ARMOR Header containing a new ARMOR Token for use with subsequent HTTP requests:

ArmorResponse

Decorating POST, PUT, and DELETE Endpoints with ARMOR

In an MVC Controller simply decorate your endpoints as follows:

[MvcArmorAuthorize]

And in Web API Controllers:

[WebApiArmorAuthorize]

Integrating Your Application’s Authentication Mechanism

AMROR operates on the basis of Claims and provides default implementations of Claim-parsing components derived from the IdentityReader class in the following classes:

  • MvcIdentityReader
  • WebApiIdentityReader

Both classes return an enumerated list of Claim objects consisting of a UserId Claim. In the case of MVC, the Claim is derived from the ASP.NET intrinsic Identity.Name property, assuming that the user is already authenticated. In the case of Web API, it is assumed that you leverage an instance of ClaimsIdentity as your default IPrincipal object, and that user metadata is stored in Claims held within that ClaimsIdentity. As Such, the WebApiIdentityReader simply extracts the UserId Claim. Both UserId and Timestamp Claims are the only default Claims in an ArmorToken and are loaded upon creation.

If your application leverages a different authentication mechanism, you can simply derive from the default IdentityReader class with your own implementation and extract your logged in user’s metadata, injecting it into Claims necessary for ARMOR to manage. Here is the default Web API implementation.

public override bool TryRead(out IEnumerable<Claim> identity) {
    var claims = new List<Claim>();
    identity = claims;

    var claimsIdentity = principal.Identity as ClaimsIdentity;
    if (claimsIdentity == null) return false;

    var subClaim = claimsIdentity.Claims.SingleOrDefault(c => c.Type.Equals(“UserId”));
    if (subClaim == null) return false;

    claims.Add(subClaim);
    return true;
}

ARMOR downcasts the intrinsic HTTP IPrincipal.Identity object as an instance of ClaimsIdentity and extracts the UserId Claim. Deriving from the IdentityReader base class allows you to implement your own mechanism to build Claims. It’s worth noting that you can store many Claims as you like in an ARMOR Token. ARMOR will decrypt and deserialise your Claims so that they can be read on the return journey back to server from UI.

Adding ARMOR UI Components

The ARMOR WebFramework contains a JavaScript file as follows:

var ajaxManager = ajaxManager || {
    setHeader: function(armorToken) {
    $.ajaxSetup({
        beforeSend: function(xhr, settings) {
            if (settings.type !== “GET”) {
                xhr.setRequestHeader(“Authorization”, “ARMOR “ + armorToken);
            }
        }
    });
}
};

The purpose of this code is to detect the HttpRequest type, and apply an ARMOR Authorization Header for POST, PUT and DELETE requests. You can leverage this on each page of your application (or in the default Layout page) as follows:

<script>
$(document).ready(function () {
ajaxManager.setHeader($(“#armorToken”).val());
});

$(document).ajaxSuccess(function (event, xhr, settings) {
    var armorToken = xhr.getResponseHeader(“ARMOR”) || $(“#armorToken”).val();
    ajaxManager.setHeader(armorToken);
});
</script>

As you can see, the UI contains a hidden field called “armorToken”. This field needs to be populated with an ArmorToken when the page is initially served. The following code in the ARMOR API itself facilitates this:

        public bool TryFortify() {
            var identityReader = identityReaderFactory.Create();
            IEnumerable<Claim> identity;

            var isAuthenticated = identityReader.TryRead(out identity);
            if (!isAuthenticated) return false;

            var claims = identity.ToList();

            var userId = claims.Single(c => c.Type.Equals("UserId")).Value;
            var platform = claims.SingleOrDefault(c => c.Type.Equals("Platform"));

            var encryptionKey = ArmorSettings.EncryptionKey;
            var hashingKey = ArmorSettings.HashingKey;

            var nonceGenerator = new NonceGenerator();
            nonceGenerator.Execute();

            var armorToken = new ArmorToken(userId,
                platform == null ? "ARMOR" : platform.Value,
                nonceGenerator.Nonce);

            var armorTokenConstructor = new ArmorTokenConstructor();
            var standardSecureArmorTokenBuilder =
                new StandardSecureArmorTokenBuilder(armorToken, encryptionKey,
                    hashingKey);
            var generateSecureArmorToken =
                new GenerateSecureArmorToken(armorTokenConstructor,
                    standardSecureArmorTokenBuilder);

            generateSecureArmorToken.Execute();

            httpContext.Response.AppendHeader("ARMOR",
                generateSecureArmorToken.SecureArmorToken);
            return true;
        }

Here we generate the initial ARMOR Token to be served when the application loads. This Token will be leveraged by the first AJAX request and refreshed on each subsequent request. The Token is then loaded into the ViewBag object and absorbed by the associated View:


<div><input id=“armorToken” type=“hidden” value=@ViewBag.ArmorToken /></div>

Now your AJAX requests are decorated with ARMOR Authorization attributes:
ArmorRequest

Summary

Now that you’ve implemented the ARMOR WebFramework, each POST, PUT and DELETE request will persist a Rijndael-encrypted and SHA256-hashed ARMOR Token, which is validated by the server before each POST, PUT, or DELETE request decorated with the appropriate attribute is handled, and refreshed after each request completes. The simple UI components attach new ARMOR Tokens to outgoing requests and read ARMOR Tokens on incoming responses. ARMOR is designed to work seamlessly with your current authentication mechanism to protect your application from CSRF attacks.

Implementing the Encrypted Token Pattern by Leveraging ARMOR

Overview

Download the code on GitHub

A.R.M.O.R (Advanced Resilient Mode of Recognition) is a C# Framework designed to protect your ASP.NET web applications against CSRF attacks. This article explains how you can leverage ARMOR across an application built on MVC, Web API, or a combination of both. For more information on ARMOR or the Encrypted Token Pattern, please read this article.

The ARMOR WebFramework

The ARMOR WebFramework is a toolkit that provides boilerplate components intrinsic to ASP.NET, such as custom Authorization attributes, Filters and a range of tools to facilitate Header-parsing and other mechanisms necessary to secure your application. You can download the code here.

Securing Your Application with ARMOR

Download the Nuget package Daishi.Armor.WebFramework:

Daishi.WebFramework NuGet

Once applied, you will have full access to the ARMOR API. Implementing the API is simple, as follows.

Add the appropriate Application Configuration settings

Add the following markup to your Application Configuration file:


&lt;add key=&quot;IsArmed&quot; value=&quot;true&quot; /&gt;&lt;/b&gt;
&lt;add key=&quot;ArmorEncryptionKey&quot; value=&quot;{Encryption Key}&quot;/&gt;&lt;/b&gt;
&lt;add key=&quot;ArmorHashKey&quot; value=&quot;{Hashing Key}&quot;/&gt;&lt;/b&gt;
&lt;add key=&quot;ArmorTimeout&quot; value=&quot;1200000&quot;/&gt;&lt;/b&gt;

The keys are as follows:

  • IsArmed – Toggle feature to turn ARMOR on or off at an application-wide level
  • ArmorEncryptionKey – The key that ARMOR will use to encrypt its Tokens
  • ArmorHashKey – The key that ARMOR will use to generate a Token Hash
  • ArmorTimeout – the time in milliseconds that ARMOR Tokens are valid for after generation

That’s it, we’re done with configuration. You can generate keys as follows using the RNGCryptServiceProvider class in .NET:


byte[] encryptionKey = new byte[32];
byte[] hashingKey = new byte[32];

using (var provider = new RNGCryptoServiceProvider()) {
    provider.GetBytes(encryptionKey);
    provider.GetBytes(hashingKey);
}

Both key values are 256 bits in length and are stored in the Application Configuration file in Base64-encoded format.

Hook the ARMOR Filter to your application

There are two main components to consider in the ARMOR WebFramework

  • Authorization Filter – validates the incoming ARMOR Token
  • Fortification Filter – refreshes and reissues a new ARMOR Token

The Authorization filter reads the ARMOR Token from the HttpRequest Header and validates it against the logged in user. You can authenticate the user in any fashion you like; ARMOR assumes that your user’s Claims are loaded into the current Thread at the point of validation.

Given that the MVC and Web API use different assemblies, the ARMOR Framework provides dual components that cater for both.

In terms of Authorization:

  • MvcArmorAuthorizeAttribute
  • WebApiArmorAuthorizeAttribute
  • MvcArmorFortifyFilter
  • WebApiArmorFortifyFilter

And Fortification:

  • MvcArmorFortifyFilter
  • WebApiArmorFortifyFilter

Generally speaking, it’s ideal that you refresh the incoming Token on every request, whether that request validates the Token or not; specifically GET requests. Otherwise, the Token may expire unless the user issues a POST, PUT, or DELETE request within the Token’s lifetime.

To do this, simple register the appropriate ARMOR Fortification mechanism in your application.

For MVC controllers:


public static void RegisterGlobalFilters(GlobalFilterCollection filters) {
    filters.Add(new HandleErrorAttribute());
    filters.Add(new HandleExceptionFilter(&quot;&quot;, &quot;Error&quot;));
    filters.Add(new MvcArmorFortifyFilter());
}

As you can see, the MvcArmorFortifyFilter is now registered in MVC.

For Web API Controllers:

config.Filters.Add(new WebApiArmorFortifyFilter());

Add the above in the WebApiConfig.cs file.

Now, each HttpResponse issued by your application will contain a custom ARMOR Header containing a new ARMOR Token for use with the next HttpRequest:

ArmorResponse

Decorate your POST, PUT and DELETE endpoints with ARMOR

In an MVC Controller simply decorate your endpoints as follows:

[MvcArmorAuthorize]

And in Web API Controllers:

[WebApiArmorAuthorize]

Integrate your application’s authentication mechanism

Your application presumably has a method of authentication. AMROR operates on the basis of Claims and provides default implementations of Claim-parsing components derived from the IdentityReader class in the following classes:

  • MvcIdentityReader
  • WebApiIdentityReader

Both classes return an enumerated list of Claim objects consisting of a UserId Claim. In the case of MVC, the Claim is derived from the ASP.NET intrinsic Identity.Name property, assuming that the user is already authenticated. In the case of Web API, it is assumed that you leverage an instance of ClaimsIdentity as your default IPrincipal object, and that user metadata is stored in Claims held within that ClaimsIdentity. As Such, the WebApiIdentityReader simply extracts the UserId Claim. Both UserId and Timestamp Claims are the only default Claims in an ArmorToken and are loaded upon creation.

If your application leverages a different authentication mechanism, you can simply derive from the default IdentityReader class with your own implementation and extract your logged in user’s metadata, injecting it into Claims necessary for ARMOR to manage. Here is the default Web API implementation. As you can see, the code is very straightforward:

public override bool TryRead(out IEnumerable&lt;Claim&gt; identity) {
    var claims = new List&lt;Claim&gt;();
    identity = claims;

    var claimsIdentity = principal.Identity as ClaimsIdentity;
    if (claimsIdentity == null) return false;

    var subClaim = claimsIdentity.Claims.SingleOrDefault(c =&gt; c.Type.Equals(&quot;UserId&quot;));
    if (subClaim == null) return false;

    claims.Add(subClaim);
    return true;
}

ARMOR downcasts the intrinsic HTTP IPrincipal.Identity object as an instance of ClaimsIdentity and extracts the UserId Claim. Deriving from the IdentityReader base class allows you to implement your own mechanism to build Claims. It’s worth noting that you can store as many Claims as you like in an ARMOR Token, so feel free to do so. ARMOR will decrypt and deserialise your Claims so that they can be read on the return journey back to the server from the UI.

Adding the ARMOR UI Components

The ARMOR WebFramework contains a JavaScript file as follows:

var ajaxManager = ajaxManager || {
    setHeader: function(armorToken) {
        $.ajaxSetup({
            beforeSend: function(xhr, settings) {
                if (settings.type !== &quot;GET&quot;) {
                    xhr.setRequestHeader(&quot;Authorization&quot;, &quot;ARMOR &quot; + armorToken);
                }
            }
        });
    }
};

The purpose of this code is to detect the HttpRequest type, and apply an ARMOR Authorization Header for POST, PUT and DELETE requests. You can leverage this on each page of your application (or in the default Layout page) as follows:

&lt;script&gt;
    $(document).ready(function () {
        ajaxManager.setHeader($(&quot;#armorToken&quot;).val());
    });
    $(document).ajaxSuccess(function (event, xhr, settings) {
        var armorToken = xhr.getResponseHeader(&quot;ARMOR&quot;) || $(&quot;#armorToken&quot;).val();
        ajaxManager.setHeader(armorToken);
    });
&lt;/script&gt;

As you can see, the UI contains a hidden field called “armorToken”. This field needs to be populated with an ArmorToken when the page is initially served. The following code in the ARMOR API itself facilitates this:

var nonceGenerator = new NonceGenerator();
nonceGenerator.Execute();

var encryptionKey = Convert.FromBase64String(ConfigurationManager.AppSettings[&quot;ArmorEncryptionKey&quot;]);

var hashingKey = Convert.FromBase64String(ConfigurationManager.AppSettings[&quot;ArmorHashKey&quot;]);
var armorToken = new ArmorToken(User.Identity.Name, &quot;MyApp&quot;, nonceGenerator.Nonce);
var armorTokenConstructor = new ArmorTokenConstructor();

var standardSecureArmorTokenBuilder = new StandardSecureArmorTokenBuilder(armorToken, encryptionKey, hashingKey);

var generateSecureArmorToken = new GenerateSecureArmorToken(armorTokenConstructor, standardSecureArmorTokenBuilder);

generateSecureArmorToken.Execute();

ViewBag.ArmorToken = generateSecureArmorToken.SecureArmorToken;

Here we generate the initial ARMOR Token to be served when the application loads. This Token will be leveraged by the first AJAX request and refreshed on each subsequent request. The Token is loaded into the ViewBag object and absorbed by the associated View:

&lt;div&gt;&lt;input id=&quot;armorToken&quot; type=&quot;hidden&quot; value=@ViewBag.ArmorToken /&gt;&lt;/div&gt;

Now your AJAX requests are decorated with ARMOR Authorization attributes:

ArmorRequest

Summary

Now that you’ve implemented the ARMOR WebFramework, each POST, PUT and DELETE request will persist a Rijndael-encrypted and SHA256-hashed ARMOR Token, which is validated by the server before each POST, PUT, or DELETE request decorated with the appropriate attribute is handled, and refreshed after each request completes. The simple UI components attach new ARMOR Tokens to outgoing requests and read ARMOR Tokens on incoming responses. ARMOR is designed to work seamlessly with your current authentication mechanism to protect your application from CSRF attacks.

Connect with me:

RSSGitHubTwitter
LinkedInYouTubeGoogle+

Leveraging the Encrypted Token Pattern

Overview

Download the code on GitHub

CSRF attacks involve leveraging user’s authenticated state in order to invoke malicious attacks, with the general purpose of manipulating data. There are two established approaches designed to prevent such attacks:

  1. Synchronizer Token Pattern
  2. Double-Submit Cookie Pattern

For more information on these, please visit the following resource:

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

Both approaches succeed in preventing CSRF attacks, while introducing architectural and security consequences. Below is a brief synopsis.

Synchronizer Token Pattern

This pattern is recommended by owasp.org as the method of choice in preventing CSRF attacks, and is leveraged by CSRFGuard. While successfully preventing CSRF attacks, it introduces an architectural concern, in that the framework requires session state on web servers. This incurs two issues:

  1. Session-state costs memory
  2. Sessions result in an imbalance in terms of load distribution across web servers

While sessions generally cost a nominal amount of memory, significant user-load can exponentially increase that memory footprint. In general, it is best-practice to avoid sessions. More importantly, if a user has an active session on a specific web server, load-balancers will generally route that user’s subsequent requests to that specific server instead of distributing requests evenly. This results in over-utilization of that server and potential underutilization of adjacent servers. This feature can be disabled on load-balancers (generally), however doing so will result in associated sessions created on more than one web server for a specific user. This will cause synchronization issues, and require implementation of a session management tool to avoid loss of cached data across web servers.

Double-Submit Cookie Pattern

This pattern is a more lightweight implementation of CSRF-protection. While relatively new and generally considered somewhat untested (it’s just as effective as the Synchronizer Token Pattern in my opinion; the arguments against it are weak at best), it achieves protection while avoiding the use of state. The implementation of this pattern, like the Synchronizer Token Pattern, produces design and security consequences:

  1. Cookies cannot be tagged as HTTPONLY
  2. Potential XSS vulnerabilities in subdomains can introduce poisoned cookies in upper domains

Cookies that contain sensitive server metadata, such as session cookies, should be tagged as HTTPONLY. This prevents client-side scripts from reading values from the cookie, adding a layer of protection. Given that this pattern requires client-side scripts to read the token from the cookie and apply it to the HTTP header, we cannot tag the cookie as HTTPONLY, introducing a potential security concern.

Leveraging this pattern requires that all software in our suite of applications are fully XSS-resistant. If an application in a subdomain, below our application domain, is compromised within the context of an XSS attack, an attacker could potentially introduce a poisoned cookie to that site, which would be valid in our upper domain, and allow an attacker to circumnavigate our CSRF protection framework.

Conclusion

Both methods of protection introduce design and potential security consequences. As a result, I’ve created a new pattern, the Encrypted Token Pattern, to address these concerns.

Encrypted Token Pattern

This pattern addresses the shortfalls of both the Synchronizer Token Pattern and the Double-Submit Cookie Pattern as follows:

  • It does not require server-state
  • It does not require cookies
  • It does not require two tokens
  • It does not require any effort on the client-side other than including the token in HTTP requests
  • It does not require any other application in a subdomain to be XSS-proof

The Encrypted Token Pattern is described here.

Summary

The Encrypted Token Pattern solves the shortfalls of other CSRF protection patterns and allows us greater control over CSRF-defense, without introducing new security concerns or architectural problems.

Check out this post for a simple walkthrough outlining the steps involved in leveraging ARMOR to protect your application against CSRF attacks.

Connect with me:

RSSGitHubTwitter
LinkedInYouTubeGoogle+