Web security with CloudFront
"There’s no silver bullet solution with cybersecurity, a layered defense is the only viable defense." – James Scott
In this article, Senior Staff Engineer Juan Lulkin and DevOps Engineer Soukaina Ait said oubrahim, fill us in on optimizing security using web security headers with CloudFront, why it matters, and how we tested and implemented them at Choco.
Let's begin with a story
One beautiful day you wake up, do your morning chores and go to work. While debugging a problem in production you notice a request to a strange domain in the network tab. Curious. You ask around. Nobody is aware of such a thing.
Determined to figure this out, you track down which part of the code is doing such calls. The culprit is hard to find, and after some time you learn the request is coming from a dependency, of a dependency ... of a dependency.
You look this dependency up, Google around and find people chatting over Hackernews that a new npm exploit was just found. It turns out this dependency is sending user information to a 3rd party domain.
You turn on incident response mode, call an incident and mitigate the problem by removing the dependency, which involves downgrading a bunch of other dependencies and deploying a patch.
You talk to the company security team and data privacy officer. They explain you'll have to find out exactly which users have had data compromised and what data was leaked because they will have to notify all the users of the data breach. The documents are extensive and you can say goodbye to your weekend plans.
Security headers
The story above might not happen every day, but the damage of it happening even once is too big not to prepare for it.
The attack vectors are plenty. npm exploits by hacking into dependencies, or using typo library names, XSS – cross site scripting –, malicious browser extensions, and many others can ruin your weekend plans and put your company's reputation at risk.
Security is about layers of defense and web security headers can go a long way when other tools might fail you. In particular, the CSP – Content Security Policy – header can be helpful to block your page from sending information to domains you don't allow. Here are some further examples.
content-security-policy: Allows loading assets and establishing connections only from whitelisted domains.
permissions-policy: Prohibits the usage of special browser features such as location, camera, microphone, etc.
referrer-policy: Prohibits passing cross-origin referrers around.
strict-transport-security: Tells browser we only do HTTPS, preload allows browsers to cache this. Once deployed you have to register your domain here.
x-content-type-options: Prevents mime-type sniffing. An old-school attack, but why not.
x-frame-options: Defines how your site can be embedded in iframes.
x-xss-protection: XSS protection for browsers that do not implement CSP. Pay attention to this issue because X-XSS-Protection: header should be disabled by default helmetjs/helmet#230.
expect-ct: Blocks misused certificates.
Web security headers with Cloudfront
Until November 2021 it was a bit of a hassle to properly add security headers to your Cloudfront distribution. If you google it you'll find articles on how to set up Cloudfront functions or Lambda at edge, requiring you to write code, test, and wire things correctly.
Now, we can use a feature that was recently announced by the AWS, which allows you to manage response headers policies used by Cloudfront distributions.
Here's a basic example:
In the example above, we're setting all the default headers AWS provides out of the box. You can read more about the individual parameters in AWS documentation. The basic config also supports CORS, in case this is not already set up in your origin, usually an S3 bucket:
Rolling it out
When rolling your headers into production, you might want to enable them in report mode. This is supported by the CSP and the expect-ct headers. In report mode, no domain will be blocked, but violations will be reported to a configurable endpoint. This step is a good way to ensure you didn't miss any relevant 3rd party and avoid errors in production.
In CSP, you'll have to change the header name from content-security-policy
to content-security-policy-report-mode
, while in the expect-ct
, the report mode is set as part of its value. Unfortunately, AWS doesn't provide defaults for these headers – nor for permission-policy –, but you can set them as custom ones:
Several error reporting tools, like Sentry, have CSP and expect-ct reporting features.
Once you're certain all the domains you allow are part of your CSP you can move it to the 'SecurityHeadersConfig' block.
Conclusion: Easy, safe and scalable
In the old days, adding security headers was something you would do in your nginx gateway or in your services, using handy plugins. But hosting your web stack on CloudFront has the advantage of out-of-the-box scalability and global reach.
Now with the introduction of security headers, AWS made it super easy to be both safe and scalable. At Choco, we're super happy with the combo.
--
Interested in learning more about the technology we use? Feel free to reach out to us directly or check out our open roles and consider joining the team.