Skip to content

Instantly share code, notes, and snippets.

@alfredlucero
Last active August 13, 2020 23:15
Show Gist options
  • Save alfredlucero/392d2360026ae1d3b994ac774f3bea92 to your computer and use it in GitHub Desktop.
Save alfredlucero/392d2360026ae1d3b994ac774f3bea92 to your computer and use it in GitHub Desktop.
Security Headers Lambda
"use strict";
const path = require("path");
const formSpaceSeparatedList = (list) => list.join(" ");
// For scripts we want to be able to load in our app i.e. third-party scripts, app scripts
const scriptSrcAllowlist = [
// https://somescript.com...
];
const generateScriptSrcPolicy = () => {
return `'self' ${formSpaceSeparatedList(scriptSrcAllowlist)}`;
};
// For styles we want to be able to load in our app
const styleSrcAllowlist = [
// https://somestyles.com...
];
const generateStyleSrcPolicy = () => {
return `'self' ${formSpaceSeparatedList(styleSrcAllowlist)}`;
};
// For fonts we want to allow in our app
const fontSrcAllowlist = [
// https://somefonts.com...
];
const generateFontSrcPolicy = () => {
return `'self' ${formSpaceSeparatedList(fontSrcAllowlist)}`;
};
// For endpoints we would like to connect to i.e. make XHR requests, Events, WebSockets in our app
const connectSrcAllowlist = [
// https://someendpointdomainswecall...
];
const generateConnectSrcPolicy = () => {
return `'self' ${formSpaceSeparatedList(connectSrcAllowlist)}`;
};
// For things we allow to be loaded up in an iframe
const frameSrcAllowlist = [
// https://somethingsweloadiniframe...
];
const generateFrameSrcPolicy = () => {
return `'self' ${formSpaceSeparatedList(frameSrcAllowlist)}`;
};
// For image references we allow to load up in our app
const imageSrcAllowlist = [
// https://someimages...
];
const generateImageSrcPolicy = () => {
return `'self' ${formSpaceSeparatedList(imageSrcAllowlist)}`;
};
exports.handler = (event, context, callback) => {
// Get contents of response
// Response event docs: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html
const response = event.Records[0].cf.response;
const headers = response.headers;
// Set new security headers
headers["strict-transport-security"] = [
{
key: "Strict-Transport-Security",
value: "max-age=63072000; includeSubdomains; preload",
},
];
// This is useful to set as report only for us to test safely so we don't accidentally break things in an environment
// due to blocked scripts, images, and the like
// Uncomment this report only one to use it and comment out the Content-Security-Policy header
// headers["content-security-policy-report-only"] = [
// {
// key: "Content-Security-Policy-Report-Only",
// value: `default-src 'self'; img-src ${generateImageSrcPolicy()}; script-src ${generateScriptSrcPolicy()}; style-src ${generateStyleSrcPolicy()}; font-src ${generateFontSrcPolicy()}; connect-src ${generateConnectSrcPolicy()}; frame-src ${generateFrameSrcPolicy()}; object-src 'none';`,
// },
// ];
headers["content-security-policy"] = [
{
key: "Content-Security-Policy",
value: `default-src 'self'; img-src ${generateImageSrcPolicy()}; script-src ${generateScriptSrcPolicy()}; style-src ${generateStyleSrcPolicy()}; font-src ${generateFontSrcPolicy()}; connect-src ${generateConnectSrcPolicy()}; frame-src ${generateFrameSrcPolicy()}; object-src 'none';`,
},
];
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);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment