Last active
August 13, 2020 23:15
-
-
Save alfredlucero/392d2360026ae1d3b994ac774f3bea92 to your computer and use it in GitHub Desktop.
Security Headers Lambda
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"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