Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding CSP headers with a nonce to Lambda Edge

I am an Ops person setting up a website that needs to have security headers implemented.

I have created a Lambda@Edge function with the headers I need which works fine, but I want to add a nonce for style-src as we are calling external URL's (google fonts etc). Most of the guides I have found are only using 'self' and not other URL's. There is one other question about this on SO but the response does not work as I am using Origin Request not Origin Response.

Can I add this to the Lambda@Edge function? I have some nodejs code that generates a nonce, but when I try to add it to the style-src section, it ignores it. I do not know JS so this is difficult for me to troubleshoot.

I'm open to any method of using nonces with CSP and Lambda@Edge if this is not the correct/best way.

This is my Lambda@Edge code.

'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 'self'; frame-ancestors 'none'; connect-src https://dev.example.io https://api.exampleapi.io; img-src 'self' data: https://examplebucket.s3.region.amazonaws.com; script-src 'self'; font-src 'self' https://fonts.example.com; style-src 'self' https://fonts.example.com; 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);
};

This is the code I have for generating a nonce, that works locally.

const crypto = require('crypto');
let nonce = crypto.randomBytes(16).toString('hex');
like image 698
Shangela Wadley Avatar asked Sep 17 '26 01:09

Shangela Wadley


1 Answers

I noticed that when you are using the CloudFront events Origin Request or Origin Response as triggers for your lambda@edge function, you would generate a nonce only in the case if there is a cache miss. But as I understand you would need a nonce for every HTTP request. This would suggest that you would need to use one of the other events (Viewer Request or Viewer Response), but this on the other hand would trigger your function for every HTTP request (regardless if the object you request is in cache), what might generate high costs regarding the amount of visits to your site.

AWS describes all CloudFront events in detail here: CloudFront Events That Can Trigger a Lambda Function

One thing you did not mention here is that the nonce would not only need to be generated for the CSP header, but the nonce would also need to be added to your HTML page (e.g. by replacing all <script> tags with <script nonce="r@nd0m">. It's possible to do this in your lambda@edge function by reading the desired object from your S3 bucket and replacing all script tags as described above. But then you need to be aware of AWS lambda@edge limits (e.g. the size of a response that is generated by a Lambda function). Check the limits here: Restrictions on using Lambda functions with CloudFront

I've already found solutions that do not use lambda@edge functions when creating CSP with nonces. So instead of using lambda@edge, you e.g. use API Gateway with Lambda. See here (Attempt 3: Route53, CloudFront, S3, API Gateway, Lambda): My experience getting an A+ from Mozilla’s Observatory tool on AWS

like image 159
TNT-Boy Avatar answered Sep 18 '26 15:09

TNT-Boy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!