.NET Core Middleware – OWASP Headers Part 2 – Configuration

Today’s header image was created by Jeremy Bishop, the original source for the image is available here

Caveat

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.

it’s why we included a global.json file in the root of the source code, last time

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.

Anyway, back to the article.


Remember the last time I wrote about OwaspHeaders.Core?

it wasn’t that long ago; here’s a link in case you missed it

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.

Injecting Headers

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.

don’t remember who they are? Go take a look at their website

Injecting a single header can be useful,

my first ever NuGet package is all about injecting a single header

but only to a certain extent. Especially the ham-fisted way we were injecting the HSTS header.

Here’s a quick reminder of the middleware class we wrote:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Abstractions;
namespace OwaspHeaders.Core
{
/// <summary>
/// A middleware for injecting OWASP recommended headers into a
/// HTTP Request
/// </summary>
public class SecureHeadersMiddleware
{
private readonly RequestDelegate _next;
public SecureHeadersMiddleware(RequestDelegate next)
{
_next = next;
}
/// <summary>
/// The main task of the middleware. This will be invoked whenever
/// the middleware fires
/// </summary>
/// <param name="HttpContext">The <see cref="HttpContext" /> for the current request or response</param>
/// <returns></returns>
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 at this 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 readonly string 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 called HttpContextExtensions.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(headerName, headerValue);
return true;
}
catch (ArgumentException)
{
return false;
}
}
  • Check whether the header already exists by calling ResponseContainsHeader (which is a wrapper around ContainsKey). If so, we return true.
  • Attempt to add the header and value to the Header dictionary (and return true if we can)
  • Return false if we catch an ArgumentException

We can use the TryAddHeader extension method in our middleware’s Invoke method to make it easier to check and add each header value.

Let’s do that now:

// no check needed
public async Task Invoke(HttpContext httpContext)
{
httpContext.TryAddHeader(Constants.StrictTransportSecurityHeaderName,
"max-age=31536000; includeSubDomains");
// Call the next middleware in the chain
await _next.Invoke(httpContext);
}

Isn’t that easier to read?

Configuration

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.

We’ll load the configuration from a JSON file

but .NET Core will do the heavy lifting for us, so it could be an XML or INI file

which we’ll include with the application which consumes our middleware. That way we leave the configuration up to the consumer of the middleware.

Here is an example of what our configuration will look like:

{
"SecureHeadersMiddlewareConfiguration": {
"UseHsts": "true",
"HstsConfiguration": {
"MaxAge": 31536000,
"IncludeSubDomains": "true"
}
}
}

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.

By “us” and “we”, I mean the middleware class

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.

The SecureHeadersMiddlewareConfiguration Class

Create a directory in the OwaspHeaders.Core source directory (along side the csproj) called Models, create a file in there called ISecureHeadersMiddlewareConfiguration.cs and paste the following code into it:

namespace OwaspHeaders.Core.Models
{
public interface ISecureHeadersMiddlewareConfiguration
{
bool UseHsts { get; set; }
HstsConfiguration HstsConfiguration { get; set; }
}
}

We’re creating an interface as it will be easier to mock if we decide to add unit tests.

what do you mean “if”?

In the same directory, create a file called SecureHeadersMiddlewareConfiguration.cs and paste the following code into it:

namespace OwaspHeaders.Core.Models
{
public class SecureHeadersMiddlewareConfiguration : ISecureHeadersMiddlewareConfiguration
{
/// <summary>
/// Indicates whether the response should use HTTP Strict Transport Security
/// </summary>
public bool UseHsts { get; set; }
/// <summary>
/// The HTTP Strict Transport Security configuration to use
/// </summary>
public HstsConfiguration HstsConfiguration { get; set; }
public SecureHeadersMiddlewareConfiguration()
{
UseHsts = true;
HstsConfiguration = new HstsConfiguration();
}
}
}

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?

Not yet, we need another interface first

In the same directory, create a file called IConfigurationBase.cs and paste the following code into it:

namespace OwaspHeaders.Core.Models
{
public interface IConfigurationBase
{
string BuildHeaderValue();
}
}

There’s only one more file to create now, and it lives in the same directory as the others: HstsConfiguration.cs. This time the code looks like this:

using System.Text;
namespace OwaspHeaders.Core.Models
{
/// <summary>
/// Represents the HTTP Strict Transport Security configuration
/// </summary>
public class HstsConfiguration : IConfigurationBase
{
/// <summary>
/// (OPTIONAL) Whether this rule applies to all of the site's subdomains as well
/// </summary>
public bool IncludeSubDomains { get; set; }
/// <summary>
/// The time, in seconds, that the browser should remember that this site is
/// only to be accessed using HTTPS
/// </summary>
public int MaxAge { get; set; }
public HstsConfiguration()
{
IncludeSubDomains = true;
MaxAge = 31536000;
}
/// <summary>
/// Builds the HTTP header value
/// </summary>
/// <returns>A string representing the HTTP header value</returns>
public string BuildHeaderValue()
{
var stringBuilder = new StringBuilder();
stringBuilder.Append("max-age=");
stringBuilder.Append(MaxAge);
stringBuilder.Append(IncludeSubDomains ? "; includeSubDomains" : string.Empty);
return stringBuilder.ToString();
}
}
}

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.

public string BuildHeaderValue()
{
var stringBuilder = new StringBuilder();
stringBuilder.Append("max-age=");
stringBuilder.Append(MaxAge);
stringBuilder.Append(IncludeSubDomains ? "; includeSubDomains" : string.Empty);
return stringBuilder.ToString();
}

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#.

you can read more about strings being immutable in C# here

Consuming the SecureHeadersMiddlewareConfiguration

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.

wait, I’ve heard of those 😛

Edit the SecureHeadersMiddleware.cs file, replacing it’s contents with the following:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using OwaspHeaders.Core.Extensions;
using OwaspHeaders.Core.Models;
namespace OwaspHeaders.Core
{
/// <summary>
/// A middleware for injecting OWASP recommended headers into a
/// HTTP Request
/// </summary>
public class SecureHeadersMiddleware
{
private readonly RequestDelegate _next;
private readonly SecureHeadersMiddlewareConfiguration _config;
public SecureHeadersMiddleware(RequestDelegate next, SecureHeadersMiddlewareConfiguration config)
{
_next = next;
_config = config;
}
/// <summary>
/// The main task of the middleware. This will be invoked whenever
/// the middleware fires
/// </summary>
/// <param name="HttpContext">The <see cref="HttpContext" /> for the current request or response</param>
/// <returns></returns>
public async Task Invoke(HttpContext httpContext)
{
if (_config == null)
{
throw new ArgumentException([email protected]"Expected an instance of the
{nameof(SecureHeadersMiddlewareConfiguration)} object.");
}
if (_config.UseHsts)
{
httpContext.TryAddHeader(Constants.StrictTransportSecurityHeaderName,
_config.HstsConfiguration.BuildHeaderValue());
}
// Call the next middleware in the chain
await _next.Invoke(httpContext);
}
}
}

Let’s take a look at some of the changes we’ve made in a little more detail:

public class SecureHeadersMiddleware
{
private readonly RequestDelegate _next;
private readonly SecureHeadersMiddlewareConfiguration _config;
public SecureHeadersMiddleware(RequestDelegate next, SecureHeadersMiddlewareConfiguration config)
{
_next = next;
_config = config;
}

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.

public async Task Invoke(HttpContext httpContext)
{
if (_config == null)
{
throw new ArgumentException([email protected]"Expected an instance of the
{nameof(SecureHeadersMiddlewareConfiguration)} object.");
}
if (_config.UseHsts)
{
httpContext.TryAddHeader(Constants.StrictTransportSecurityHeaderName,
_config.HstsConfiguration.BuildHeaderValue());
}
// Call the next middleware in the chain
await _next.Invoke(httpContext);
}

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.

you can change this in your version of the middleare class if you wish

We’re also (in the second highlighted section) making use of the SecureHeadersMiddlewareConfiguration object and the BuildHeaderValue method on it’s HstsConfiguration object.

Consuming OwaspHeaders.Core

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.

take a look at this section of the previous part, for a refresher

In that example project, there will be a startup.cs file which will look like the following:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using OwaspHeaders.Core;
namespace example
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMiddleware<SecureHeadersMiddleware>();
app.UseMvc();
}
}
}

I’ve highlighted the line where we’re consuming the our middleware

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.

If you don’t know what they are, I’ve got an article all about them in the pipeline (pun intended)

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.

This process WILL change with the release of .NET Core 2.0

Open the example project’s Startup.cs file and replace its contents with the following:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OwaspHeaders.Core.Extensions;
using OwaspHeaders.Core.Models;
namespace OwaspHeaders.Core.Example
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("secureHeaderSettings.json", optional:true, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
// Add functionality to inject IOptions<T>, we'll need this for our middleware
services.AddOptions();
// Add our SecureHeadersMiddlewareConfiguration object so it can be injected
services.Configure<SecureHeadersMiddlewareConfiguration>(
Configuration.GetSection("SecureHeadersMiddlewareConfiguration"));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory,
IOptions<SecureHeadersMiddlewareConfiguration> secureHeaderSettings)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMiddleware<SecureHeadersMiddleware>(secureHeaderSettings.Value);
app.UseMvc();
}
}
}

There’s a lot that has changed here, so let’s take a look at some of the changes in greater detail:

public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddJsonFile("secureHeaderSettings.json", optional:true, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}

Here we’re telling .NET Core to look in the root directory of the application for our secureHeaderSettings.json file.

note: .NET Core uses the root directory because we used .UseContentRoot(Directory.GetCurrentDirectory()) in our Program.cs file

public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
// Add functionality to inject IOptions<T>, we'll need this for our middleware
services.AddOptions();
// Add our SecureHeadersMiddlewareConfiguration object so it can be injected
services.Configure<SecureHeadersMiddlewareConfiguration>(
Configuration.GetSection("SecureHeadersMiddlewareConfiguration"));
}

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?

public void Configure(IApplicationBuilder app, IHostingEnvironment env,
ILoggerFactory loggerFactory,
IOptions<SecureHeadersMiddlewareConfiguration> secureHeaderSettings)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseMiddleware<SecureHeadersMiddleware>(secureHeaderSettings.Value);
app.UseMvc();
}

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.

the source code for IOptions can be found in the GitHub repo for the Microsoft.Extensions.Options namespace

The last thing we need to do is add our secureHeaderSettings.json file to the root of the example project directory. Paste the following contents into the file and we’ll be ready to go:

{
"SecureHeadersMiddlewareConfiguration": {
"UseHsts": "true",
"HstsConfiguration": {
"MaxAge": 31536000,
"IncludeSubDomains": "true"
}
}
}

Consuming the Whole Thing Proper

Running the example project (assuming that you have a terminal pointed at the example project directory):

dotnet restore
dotnet run

remember, I’m one of those folks who loves the terminal. You can run this from an IDE, if you wish

And navigating a browser to localhost on the port that you’re given

I was given 5000

and you should get a response similar to the one I was given:

Owasp Headers Core From Config
Oh. I was using Rider all along, too

To prove that these values are being pulled from our secureHeadersSettings.json file, go ahead and change the file contents.

I changed mine to the following:

{
"SecureHeadersMiddlewareConfiguration": {
"UseHsts": "true",
"HstsConfiguration": {
"MaxAge": 42,
"IncludeSubDomains": "false"
}
}
}

Then restarted the example project and went back to localhost and got the following:

Owasp Headers Core From Config User Supplied
That’s pretty cool

Conclusion

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.

Related Posts

A .NET developer specialising in ASP.NET MVC websites and services, with a background in WinForms and Games Development.

When not programming using .NET, he is either learning about .NET Core (and usually building something cross platform with it), speaking Japanese to anyone who’ll listen, learning about languages, writing for his non-dev blog, or writing for a blog about video games (which he runs with his brother)