AWS Security Headers – done, right?

So a couple of days ago, I had a free half hour, so decided to check that the open source JavaScript libraries I use in my various websites were up to date. Rather than open up the base source files and check, I decided to be hip and use Firefox’s Developer Tools console window instead, when suddenly…


it displayed a couple of security issues. It seemed my HTTP security headers were out of date, probably because I didn’t check the last time I’d made a change to one of my websites. Smack: test your fixes next time, Bucknall!

It was hosted by AWS, so I brought up that blog post that described how I’d set up those headers using Lambda@Edge, three years ago. Except, in the meantime, Amazon had changed the layouts of the required apps and I was getting into issues in understanding how to fix the problem. Suddenly I was getting HTTP 503 errors on the website, and no clear idea why. I went back to the official blog post from Amazon that I’d originally used to see if there were any new hints, and it hadn’t been updated either. Gah!

Time to delete it all and then redo it. But … something was niggling in the back of my mind about a new way of implementing functions with AWS. I’d probably pretty much ignored it: after all, my functions were working fine, so why change? Right? Yeah, well.

A bit of googling later, I discover that AWS really had made the whole process way easier: they’d added request/response functions directly to CloudFront back in May this year, so there was no longer any need to use Lambda@Edge any more. And it really was easier.

So, here’s how to add the security headers to CloudFront directly. Sign in to AWS and bring up the CloudFront service page. In the side menu there’s a new option: Functions. Click on that to display a list of your functions. Click on the Create function option, it asks you for a name, so I used AddSecurityHeaders. Then it asks you for the code (just replace the example code it gives you):

function handler(event) {
    //Get contents of response
    var response = event.response;
    var headers = response.headers;

    //Set new headers 
    headers['strict-transport-security'] = {value: 'max-age=31536000; includeSubdomains; preload'}; 
    headers['content-security-policy'] = {value: "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; font-src 'self'; object-src 'none'"}; 
    headers['x-content-type-options'] = {value: 'nosniff'}; 
    headers['x-frame-options'] = {value: 'DENY'}; 
    headers['x-xss-protection'] = {value: '1; mode=block'}; 
    headers['referrer-policy'] = {value: 'same-origin'}; 
    //Return modified response
    return response;

Pretty similar all told to my original Lambda@Edge code from that old blog post, but a little simpler. This time CloudFront will call the function with the event object, you get the response object from that, modify it with the new headers, and then return the modified response.

Click Save and then Publish. It tells you that once published, you then can associate this new function with one or more of your distributions. So publish it, and then scroll down to click Add association. Pretty simple: select one of your distributions, choose the Event type (Viewer Request or Viewer Response) – in this case, it’ll be Viewer Response – and then the Cache behavior (basically select Default). Click Add association and it’s done.

If you now go back to your CloudFront distribution list you’ll see that it is in the middle of deploying said function. Wait for it to deploy and then test the website. Of course, I then associated the same function to my other distributions/websites, and removed all of that Lambda@Edge stuff as I went.

Phew! Now, where was I? Oh yes, updating JavaScript libraries…

Lion gargoyle

Loading similar posts...   Loading links to posts on similar topics...

No Responses

Feel free to add a comment...

Leave a response

Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.

  •  Emphasize with italics: surround word with underscores _emphasis_
  •  Emphasize strongly: surround word with double-asterisks **strong**
  •  Link: surround text with square brackets, url with parentheses [text](url)
  •  Inline code: surround text with backticks `IEnumerable`
  •  Unordered list: start each line with an asterisk, space * an item
  •  Ordered list: start each line with a digit, period, space 1. an item
  •  Insert code block: start each line with four spaces
  •  Insert blockquote: start each line with right-angle-bracket, space > Now is the time...
Preview of response