Quantcast
Channel: CodeSection,代码区,网络安全 - CodeSec
Viewing all articles
Browse latest Browse all 12749

.NET Core Middleware OWASP Headers Part 2 Configuration

$
0
0
using System; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Abstractions; namespace OwaspHeaders.Core { /// /// A middleware for injecting OWASP recommended headers into a /// HTTP Request /// public class SecureHeadersMiddleware { private readonlyRequestDelegate _next; public SecureHeadersMiddleware(RequestDelegate next) { _next = next; } /// /// The main task of the middleware. This will be invoked whenever /// the middleware fires /// /// The for the current request or response /// public async Task Invoke(HttpContext httpContext) { httpContext.Response.Headers.Add("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); // Call the next middleware in the chain await _next.Invoke(httpContext); } } } Let’s Refactor

Before we add more headers, let’s talk about what’s wrong with the above code. Specifically, we need to figure out what’s wrong with the following block:

public async Task Invoke(HttpContext httpContext) { httpContext.Response.Headers.Add("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); // Call the next middleware in the chain await _next.Invoke(httpContext); }

“Wrong” isn’t the correct word to use. There are two issues here, see if you can spot what they are.

psst. Take a look atthis section from the previous article in this series

The first thing that should jump out at you is the potential for an ArgumentException .

ArgumentException

The HttpContext’s Response Headers property is a Dictionary type, and you can’t have multiple instances of the same key in a Dictionary.

you can read through the source for the headers property here

When you try to insert a duplicate key into a Dictionary in C#, you get an ArgumentException.

Check the Microsoft documentation for a description of what happens when a duplicate key is added to a dictionary .

To get around this, what we need to do is check whether our header exists in the Headers dictionary before we add it. Luckily all C# dictionaries expose a method called “ContainsKey” which takes a value and checks whether the dictionary contains that key.

talk about “does what it says on the tin”

We can do this by changing the above code to match the following:

// basic headers check to avoid potential ArgumentException public async Task Invoke ( HttpContext httpContext ) { if (!httpContext.Response.Headers.ContainsKey( " Strict-Transport-Security " ) { httpContext.Response.Headers.Add( " Strict-Transport-Security " , " max-age=31536000; includeSubDomains " ); } // Call the next middleware in the chain await _next.Invoke(httpContext); }

That will do perfectly.

Except that we’ll end up copy pasting this check multiple times as we add more headers. We also have to type the name of the header twice. Let’s fix the header name issue first.

Constants

Since the header names are constant (they’re not likely to ever change, seeing as how they’re ratified against a standard), we can make them constants in our application.

Create a new file in the OwaspHeaders.Core source directory (along side the csproj) called Constants.cs and paste the following code into it:

namespace OwaspHeaders.Core { public static class Constants { public static readonlystring StrictTransportSecurityHeaderName = "Strict-Transport-Security"; } }

we’ll add to this list of constants in future parts of this series

Adding and consuming these constants means that we can simplify our header check:

// basic headers check to avoid potential ArgumentException public async Task Invoke ( HttpContext httpContext ) { if (!httpContext.Response.Headers.ContainsKey(Constants.StrictTransportSecurityHeaderName) { httpContext.Response.Headers.Add(Constants.StrictTransportSecurityHeaderName, " max-age=31536000; includeSubDomains " ); } // Call the next middleware in the chain await _next.Invoke(httpContext); }

Now let’s do something about that header check using an extension method.

Extension Methods

For those who don’t know what extension methods are:

Extension methods enable you to “add” methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. Extension methods are a special kind of static method, but they are called as if they were instance methods on the extended type

Source: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/extension-methods

If you’ve ever used LINQ, then you’ve used extension methods. They’re extremely useful, and we’re about to make one for the HttpContext object.

Create a directory in the OwaspHeaders.Core source directory (along side the csproj) called Extensions, then a file within it calledHttpContextExtensions.cs and paste the following code into it:

using System; using Microsoft.AspNetCore.Http; namespace OwaspHeaders.Core.Extensions { public static class HttpContextExtensions { public static bool ResponseContainsHeader(this HttpContext httpContext, string header) { return httpContext.Response.Headers.ContainsKey(header); } public static bool TryAddHeader(this HttpContext httpContext, string headerName, string headerValue) { if (httpContext.ResponseContainsHeader(headerName)) return true; try { httpContext.Response.Headers.Add(headerName, headerValue); return true; } catch (ArgumentException) { return false; } } } }

We’ll make use of TryAddHeader in a moment, but a quick look at how it works.

public static bool TryAddHeader(this HttpContext httpContext, string headerName, string headerValue) { if (httpContext.ResponseContainsHeader(headerName)) return true; try { httpContext.Response.Headers.Add(head

Viewing all articles
Browse latest Browse all 12749

Trending Articles