Hello, my name is: Amy

HTTP Headers as a Bad Guy

I've been playing Legend of Zelda (a lot) lately on the Nintendo Switch. (So fun!) One of the things I am great at in that game (dare I say it) is avoiding the bad guys. Fighting them gives me a crazy amount of anxiety. As I was playing, I couldn't help but think about how I have a tendency to do this in my development also. Meet today's bad guy: HTTP Headers.

While the anxiety might not be present, often my strategy of 'avoid getting into the weeds' for dealing with things I don't fully understand is the same. But over the past few weeks I've been traveling down a few web security and/or performance paths that have been dumping me at HTTP Headers. Figured it was time to roll up the sleeves and start to put this in my brain.

In the case at hand, I was trying to not fail on Mozilla's Observatory. The next step for the site I was working on was to set up 'HTTP Strict Transport Security' which involved setting a HTTP Header called 'Strict-Transport-Security'.

What exactly are HTTP Headers?

When you boil it down, here's what happens:

  • Joe types in http://mattjenkinscomic.com in a browser.
  • His computer says, OK, you want this information below. Let me go get it. (This is called the 'Request')
GET / HTTP/1.1
Host: mattjenkinscomic.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 .... Mobile Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch, br
Accept-Language: en-US,en;q=0.8
Cookie: PHPSESSID=9cs10mhllkroajsiatbigkg0b6;
DNT: 1
  • The computer that that website lives on (a server, if you will) takes in that information, and processes it. When it sends the information back to Joe's computer, it also sends along some info. (This is called the 'Response')
HTTP/1.1 200 OK
Date: Fri, 31 Mar 2017 02:33:47 GMT
Server: Apache/2.4.7 (Ubuntu)
Strict-Transport-Security: max-age=63072000; includeSubdomains;
X-Powered-By: PHP/5.5.9-1ubuntu4.21
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 5643
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html

Originally I thought that HTTP headers were just for HTML documents, but they actually accompany every single resource. Every image, javascript, css file, etc. Every request that the browser makes to the sever, and that the server sends back.

What are HTTP Headers good for?

So many things! Dealing with cache management is one thing, that's probably going to be my next tackle. Then next, if I'm feeling feisty and have sharpened my blade enough I might take a stab at setting up a Content Security Policy. Turns out I was having Apache set some headers for authentication. And cookie information is passed along in headers as well.

On a side tangent I went down related to security, I learned there's a header called Do Not Track that a user can set if they would prefer to not be tracked. Sites are supposed to honor this setting when they do things like tracking you with cookies. There's a plugin called Privacy Badger that actually sets this header for users. I use privacy badger, so you can actually see the DNT header in the above request.

How do you set HTTP Headers?


Because all of this happens before scripts are executed, you can't directly do this with javascript. But if you are requesting a new asset with an AJAX call, you can send along additional information at the time of request, if needed.


If it's just one file that needs some special instruction you can set HTTP headers with PHP individually per file.

header('Strict-Transport-Security: max-age=63072000; includeSubdomains;');

In my case, this wasn't really a option for this because ALL THE THINGS need that header.


I ended up setting my headers on my web server, which is Apache. First I had to enable mod_headers, by (a2enmod headers). Then in my .conf file (/etc/apache2/sites-available/mattjenksincomic.conf) I set the php header like so:

<VirtualHost *:443>
Header always set Strict-Transport-Security "max-age=63072000; includeSubdomains;"

How can I make sure HTTP Headers are set correctly?

You can see the requests that your page is making across the network in a browsers developer tools, usually in a 'Network' tab. More than likely you will see a mess of requests when you look at these files. It makes my brain hurt less if I filter them by type. Then you click on the name of the resource you want to look at and voila! Headers.

View of HTTP Headers in Edge

So, one bad guy slain. Maybe I'll attempt one in Zelda... mayyybe.