Just a quick note before we begin.
A caveat before we begin?
Hi everyone, this article series was written with .NET Core 1.x in mind. With the .NET Core 2.0 RTM (release to manufacturers) being right around the corner, and there being some breaking changes in 2.0, it’s worth noting that this article was written specifically for .NET Core 1.x.
Once .NET Core 2.0 has been RTMd, I’ll release an updated version of this article series where I upgrade the middleware to .NET Core 2.0. If you’ve found yourself here in the future (after 2.0 was released), I’ll add a link to the .NET Core 2.0 specific articles.
Remember the last time I wrote about OwaspHeaders.Core?
In this post I’ll be expanding on the source code we wrote together to make the whole thing a little more safe and more configurable.
Because I’ll be expanding on the code we wrote together last time, it will be extremely useful to have that code to hand. I’ll link to specific parts of the previous post in this series where necessary, but it’ll be easier for you if you have it all to hand.
if you want to jump straight to the finished source code, then head over the the GitHub repo for it.
I’d recommend reading the article, though.
In that post I walked through how to create a basic middleware which would inject a single HTTP Header into a request. The header we injected was the HTTP Strict Transport Security (HSTS) header with values which are recommended by OWASP.
but only to a certain extent. Especially the ham-fisted way we were injecting the HSTS header.
“Wrong” isn’t the correct word to use. There are two issues here, see if you can spot what they are.
The first thing that should jump out at you is the potential for an 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.
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.
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.
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.
Now let’s do something about that header check using an extension method.
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.
We’ll make use of TryAddHeader in a moment, but a quick look at how it works.
Check whether the header already exists by calling ResponseContainsHeader (which is a wrapper around ContainsKey). If so, we return true.
We can use the TryAddHeader extension method in our middleware’s Invoke method to make it easier to check and add each header value.
The next thing we’re going to do is to make our middleware configurable, and load a configuration for it from disk. This can be useful as we might have a specific set up for the server, or might not want to use all of the OWASP recommended headers.
which we’ll include with the application which consumes our middleware. That way we leave the configuration up to the consumer of the middleware.
The JSON key names will infer the names of the properties for our corresponding POCO.
We’ll have the consuming application read a JSON object to memory at application startup and pass it through to us, rather than read the JSON object from disk each time we’re called.
Reading from disk each time that a request comes in versus reading once in application start up and passing an in memory POCO has the benefit of only hitting the disk once. It does mean that we’ll have potential for a large POCO sitting in memory, but (depending on where in the pipeline we’re placed) we’d use it for every request that we deal with.
hitting the disk each time that a request comes in would be disastrous for performance.
We’re creating an interface as it will be easier to mock if we decide to add unit tests.
if you build right about now, you;’ll get errors. This is because we haven’t created the HstsConfiguration class. Guess what we’re doing next?
By creating IConfigurationBase and extending it in the HstsConfiguration class (and other classes which will represent the configurations for other headers), we can be assured that there will be a method specifically for generating the header value string.
That way we don’t have to write code where we consume the SecureHeadersMiddlewareConfiguration class in order to get the correctly formatted value string a given header class.
In the HstsConfiguration BuildHeaderValue method we’re using a StringBuilder to build up our header value. This will be more efficient than concatenating strings (i.e. “max-age=” + MaxAge), due to the fact that strings are immutable in C#.
For now we’re going to continue working on the middleware under the assumption that we’ve been passed a valid SecureHeadersMiddlewareConfiguration object.
We’ll rely on .NET Core’s built in dependency injection to pass us an instance of the SecureHeadersMiddlewareConfiguration class when we’re being constructed. If the user doesn’t supply us with a valid configuration, we’ll raise an ArgumentException.
Here we’re asking .NET Core to dependency inject an instance of the SecureHeadersMiddlewareConfiguration class when ever the consuming application constructs and instance of the SecureHeadersMiddleware class.
I’ve chosen to throw an argument exception here, because without an instance of the SecureHeadersMiddlewareConfiguration class, we can’t do anything. You could change this to call the Invoke method of the next middleware item if you wish. But it seems bad to carry on processing, if we don’t have a valid configuration.
We’re also (in the second highlighted section) making use of the SecureHeadersMiddlewareConfiguration object and the BuildHeaderValue method on it’s HstsConfiguration object.
Because the design for our middleware has changed, the old way of adding it to the pipeline isn’t going to work any more. As a refresher, in the previous part of this series we created an example webapi project to consume our middleware with.
This Startup class needs to be updated to deserialise a SecureHeadersMiddlewareConfiguration from a JSON configuration file. We’ll add a JSON file called secureHeaderSettings.json to the project and use that to store our configuration settings.
If you know about User Secrets, then we could store the configuration in a user secret, instead.
We’ll need to make use of the AddOptions extension method in order to deserialise our SecureHeadersMiddlewareConfiguration object from the secureHeaderSettings.json file and consume it in our middleware. AddOptions is an extension method for the IServicesCollection interface, and is found in the Microsoft.Extensions.DependencyInjection namespace.
The resulting SecureHeadersMiddlewareConfiguration can then be dependency injected into the Configure method in the Startup class before we pass it to the SecureHeadersMiddleware constructor.
you can read about what we’re about to do, in the Microsoft documentation at this link.
Here we’re telling .NET Core to look in the root directory of the application for our secureHeaderSettings.json file.
Here we add the AddOptions service, in order to read our SecureHeadersMiddlewareConfiguration from the secureHeaderSettings.json and so that we can use the IOptions<T> interface later.
We’re then calling GetSection from the Microsoft.Extensions.Configuration namespace in order to deserialise the secureHeaderSettings.json and parse it’s JSON object to an instance of the SecureHeadersMiddlewareConfiguration class.
This is then passed to the OptionsConfigurationServiceCollectionExtensions Configure extension method which will generate us an IOptions of type SecureHeadersMiddlewareConfiguration for us, this will then be dependency injected into the Configure method.
not bad for just two lines of code, eh?
Here we’re dependency injecting our IOptions<SecureHeadersMiddlewareConfiguration> so that we can consume it in the constructor for our middleware.
We need to use the Value property of the secureHeaderSettings variable (which is our IOptions<SecureHeadersMiddlewareConfiguration>) in our middleware constructor because the IOptions Interface contains an instance of TOptions (which can be any class) called Value.
To prove that these values are being pulled from our secureHeadersSettings.json file, go ahead and change the file contents.
We’ve taken a middleware class that we built last time, made it less likely to fall over, given it constants, and even provided it’s configuration from an external JSON file.
We learnt a little about the AddOptions and GetSection extension methods (for OptionsServiceCollectionExtensions and IConfiguration, respectively), and how they are used to load configuration data from an external JSON file during startup.
AND we’ve learnt how to use all of that to pass some configuration data to the constructor of a middleware class.
Have you passed any configuration data to a middleware class which you’ve designed and developed? How do you think we’ll implement the remaining OWASP recommended headers in the next part?
Are you more likely to create your own middleware now that you know how to pass configuration data into it?
Have you used my Clacks Middleware from NuGet yet?
how about the NuGet package for OwaspSecureHeaders.Core?
Let me know in the comments, and let’s keep the conversation going.