Configuring a Content-Security-Policy with Lambda Edge

Jesse Langford
4 min readSep 29, 2020

Recently I’ve been working on upgrading the security of my web applications. One of the easiest security features to add is a robust Content-Security-Policy.

According to MDN:

Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, including Cross Site Scripting (XSS) and data injection attacks.
Configuring Content Security Policy involves adding the Content-Security-Policy HTTP header to a web page and giving it values to control what resources the user agent is allowed to load for that page. For example, a page that uploads and displays images could allow images from anywhere, but restrict a form action to a specific endpoint. A properly designed Content Security Policy helps protect a page against a cross site scripting attack.

Adding a CSP to your web application will show you just how many external resources are being loaded by other libraries. The first site I did had a number of js libraries running inside it like Google Maps, Stripe, Intercom and Google Analytics. When first adding the libraries I was really only aware of the api endpoints / classes that I wanted to use. Once I had my content security policy I saw all the image, javascript files, fonts, and even mp3 files that these libraries need to run correctly.

To configure my CSP, I used Lambda Edge. All of the hosting for my site was on AWS so it made perfect sense.

Step 1. Create Lambda Function

First head into the AWS console and navigate to lambda. Select create and you should see a screen like this.

Provide a name and scroll down the the bottom.

Select create a new role from AWS policy templates
Give your role a name
Select the Basic Lambda@Edge option from the templates

Step 2. Add basic Content-Security-Policy

Below is a blank example of the different fields that I use in my own content-security-policy. Everyones will be different, so take some time to read about each of the different sources.

"use strict";
exports.handler = (event, context, callback) => {
//Get contents of response
const response = event.Records[0].cf.response;
const headers = response.headers;

//Set new headers
headers["strict-transport-security"] = [
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubdomains; preload",
},
];
headers['content-security-policy'] = [{key: 'Content-Security-Policy', value: "default-src 'none’; " +
"font-src ; " +
"form-action 'self'; " +
"frame-src ; " +
"media-src ; " +
"frame-ancestors 'self'; " +
"base-uri 'self'; " +
"manifest-src 'self'; " +
"img-src 'self'; " +
"style-src 'self' 'unsafe-inline'; " +
"script-src 'self'; " +
"connect-src ;"
}];
headers["x-content-type-options"] = [{ key: "X-Content-Type-Options", value: "nosniff" },];
headers["x-frame-options"] = [{ key: "X-Frame-Options", value: "DENY" }];
headers["x-xss-protection"] = [{ key: "X-XSS-Protection", value: "1; mode=block" },];
headers["referrer-policy"] = [{ key: "Referrer-Policy", value: "same-origin" },];

//Return modified response
callback(null, response);
};

Step 3. Configure CloudFront Distribution to use Lambda

Navigate to CloudFront, select the distribution that handles your website.

Inside the selected distribution, click the Behaviours tab

Inside of behaviours, scroll to the bottom and select a new event from the Lambda Function Associations

Click Yes, Edit and your CloudFront distribution will automatically redeploy. You may need to manually invalidate the objects of your distribution as well.

--

--