1. Introduction to Content Security Policy
I'm Lucas Esteveau, a lead UI engineer contractor from Avenue Code at Apple. Let's talk about why you should care about a Content Security Policy. Browsers have security features, but they can't prevent all attacks. A CSP is a layer of security that restricts browser functionality. You can implement it using meta tags or headers. In Next.js, you can add directives in your next config file.
Hi, everyone. Thanks for having me at the React Advanced Conference 2023. I'm Lucas Esteveau. I'm a lead UI engineer contractor from Avenue Code at Apple since I moved to California about four years ago. I also host a Brazilian Portuguese podcast about career in tech. So if you're curious and are a Portuguese speaker, check it out on the major streaming platforms.
I'm really excited to talk to you about how should your Next.js app with a Content Security Policy today and I want to start answering why should I care about a Content Security Policy? Well, it turns out your browser is not 100% safe. Whether it's React or Next.js or any library or framework that you might be using for your web application. Although browsers do have security built-in features like single origin policy and course and libraries and frameworks like React and Next.js do a pretty decent job sanitizing the code and providing web features to close security gaps, we can't take it for granted. If a code like this is injected in your website, your browser or React default features can't prevent this from being executed. Meaning, your app could be exposed to cross-type scripting attacks, and precious data could be leaked.
That's when a CSP comes handy. A content security policy. It's a layer for security that helps to shield applications from attacks like cross-type scripting attacks, or data injection attacks, and it does it by restricting browser functionality. A content security policy is composed by a list of policy directives. The browser will be limited to allow only what you define in your policy. So here is an example of how a content security policy is composed. Here another example, where the policy directives, where I'm defining that the default sources content, let me go back to this one. Here are examples of policy directives where I'm defining that the default sources of content should come from my domain. And I'm adding an exception for fonts, because I want to allow Google Web Fonts to be downloaded.
There are two ways to implement a content security policy in your application. The first one is by adding a meta tag in the HTML head, but this one is not preferred. The other way, and the best way to go, is to create a header for it. So here we are adding a CSP key and the value that will hold our directives. In this case, as I said before, I'm saying that the default source of my content, it's gonna come from my domain, and adding an exception for fonts that can also come from Google. When it comes to Next.js, this is how a CSP looks like. You can simply add a list of directives in your header inside your next config file. You may define what kind of requests the CSP will be applied to using the source attribute. In this case, I'm saying that my content security policy will be applied for every single request. I'm not filtering, although you could do it, filtering your API for example.
2. CSP Validation and Implementation
To validate your CSP, you can use csp-evaluator.withgoogle.com or observatory.mozilla.org. Announced allows executing inline scripts securely. Server components retrieve the announce from the header. A middleware in the Hudafor project sets the announce on the request header. The middleware defines directives and sets the CSP request header. Apply directives dynamically based on the environment. Start with report-only CSP, review the results, and enforce later. The browser sends a report with a POST request to the defined endpoint. Review the report for policy violations. Repeat the process when making changes. Find the sample Next.js app with CSP on my GitHub.
What about validation? It's pretty simple. You have pretty much two resources that you can use to validate your CSP. You can check it out going to csp-evaluator.withgoogle.com or to observatory.mozilla.org. Make sure that everything looks good, you're following the best practice, and move the code to your own app.
There will be cases when you need inline scripts. For those scenarios, announced will allow your scripts to execute without losing the security of your CSP. Announced is pretty much a random string, a hash created for one-time use. Let's see how announced can be used in a server component. On a strict CSP policy set, modern browsers will only execute scripts whose announced attribute matches the value set in the policy header. Scripts dynamically added to the page by scripts with the proper announce will also be executed.
This is how a server component looks like, as I said, getting the announce from the header. To expose the announce, we need to create a middleware in the Hudafor project and set the announce on the request header. Here we are doing this with the help of crypto. To use the announce on our policy, we can define the directives and set the CSP request header inside our middleware. We can even apply directives dynamically depending on the environment we are. Here I'm checking if I'm not in production and if I'm not, I can lose my CSP security since I'm on developing mode. This is how our middleware looks like. I know it looks a lot, but don't worry about every line of code. The idea here is that you understand the process. You can check my code on my GitHub.
But let's review it. First we create the announce, then we define our CSP and we add both to the request headers. You don't need to apply all the rules at once and risk breaking your app. You can add the report-only CSP first, reveal the results, and enforce it later. This is how a report-only CSP looks like, very similar to the regular one. The browser will send an HTTP POST request to the endpoint we define, with a report that looks like this. You can see the original policy and review what's breaking. And then you can repeat this process when you make changes to your policy. Report-only, reveal, and enforce. Thank you. I hope you found this content useful. You can find the sample Next.js app with a CSP implemented on my GitHub.
Comments