How to Set Security Headers in Your Jekyll Project
Last updated: December 10 2023As a front-end developer, it is crucial to establish secure coding habits early on. In honor of Cybersecurity Awareness Month, this article aims to assist beginner front-end developers in setting security headers for their Jekyll projects. By implementing the recommended security measures, developers can protect their websites from potential threats and ensure a safe browsing experience for their users.
Importance of Setting Security Headers
Setting security headers is essential for safeguarding your project against various vulnerabilities. However, there is no one-size-fits-all security policy for all projects. To establish an effective security policy, you must consider factors such as the strictness of the policy, the desired resource loading behavior, and other project-specific requirements.
Common Security Headers
- HSTS (HTTP Strict Transport Security): This header ensures that all communication between the browser and the server occurs over a secure HTTPS connection. Example:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
- Content-Security-Policy (CSP): This header controls the resources that a browser is allowed to load. Example:
Content-Security-Policy: default-src 'self'; script-src 'self' https://example.com; style-src 'self' https://example.com
- X-Frame-Options: This header prevents clickjacking attacks by restricting how the page can be displayed in a frame or iframe. Example:
X-Content-Type-Options: SAMEORIGIN
- X-Content-Type-Options: This header prevents MIME-sniffing. Example value: "nosniff"
- Permissions Policy: This header controls browser features that a webpage can access. Example:
Permissions-Policy: camera=()
. This example specifies that the camera is disallowed on the page and all framed pages. - X-XSS-Protection: This header is used to help mitigate cross-site scripting attacks. Example:
X-XSS-Protection: 1
. However, modern browsers rely on stronger Content-Security-Policy implemetation to prevent XSS attacks. The current best practice is not to set this header or set it to 0. Read more about this and the other security headers in the MDN docs.
CSP Complexity and Adjustments
While most security headers are straightforward, the Content-Security-Policy (CSP) requires additional attention. This is because the CSP includes directives specific to the resources your project loads content from and may necessitate constant readjustment. As your project evolves, you may need to modify the CSP to accommodate new resources and functionality.
Setting Security Headers
Let's assume that you have created a project with Jekyll and you deploy it on Netlify. To set security headers, you can follow these steps:
- Create a
_headers
file in the project's root directory. - Add all the necessary security headers using the appropriate syntax. Example:
/*
X-Content-Type-Options: nosniff
/*
Referrer-Policy: strict-origin
- In the
_config.yaml
file, add the lineinclude: ["_headers"]
. - Deploy the project on Netlify for the security headers to take effect.
Setting CSP — Two Ways
So far in my projects, I have experimented with two ways to set the Content-Security-Policy (CSP) for different projects. Please do additional research to ensure you set the CSP that suits your unique project needs.
Automatic Approach
- Install the
jekyll-content-security-policy-generator
plugin as per the instructions on its GitHub page. - The plugin automatically generates hashes for the resources (images, styles, scripts, frames) it finds on your website using the sha-256 cryptographic hash function.
- The CSP directives will be added to your project's head as a
<meta>
tag upon successful installation. - A limitation of this approach I have observed is that not all external resources are added to the CSP.
Manual Approach
When configuring the directives of the Content Security Policy (CSP) in the _headers
file, it is important to understand which external resources your website fetches content from and what you want the CSP to allow or block. Here's how you can manually approach this process:
- Determine the scripts and external resources your project fetches content from. If you only want to load resources from your domain, you need to set directives to
self
. However, if you utilize external resources like a 3rd party animation library, fonts, or images from an external cloud, you must include them in the CSP. - Utilize a tool like Report-URI CSP Wizard to identify the resources that need to be added to your allowlist in the CSP. Create an account with Report-URI and add the provided link to the head of your project. This will enable a read-only CSP that will detect items on your site, which you can then choose to allow or block from the Report-URI dashbord associated with your website. Once you have reviewed and approved these resources, you can add them to your CSP.
- Define the CSP directives in the
_headers
file alongside other security headers. It is important to note that host whitelists can frequently be bypassed. To mitigate this risk, it is recommended to use thestrict-dynamic
directive along with nonces or hashes for these resources. This ensures that only trusted scripts are executed. - If you do not have many 3rd party resources to add to your projects, you can manually handle this process to gain a better understanding of how things work. Most CDNs now come with an integrity attribute, ensuring subresource integrity by running the resources through a security hashing algorithm like sha-512. For instance, if you are using the AOS library, the CDN link will look something like this:
<script src="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.js" integrity="sha512-A7AYk1fGKX6S2SsHywmPkrnzTZHrgiVT7GcQkLGDe2ev0aWb8zejytzS8wjo7PGEXKqJOrjQ4oORtnimIRZBtw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
To ensure that the script is loaded from the correct source, you only need to include the integrity value of this script in the CSP. Repeat this process for the remaining resources you have.
Testing the Security Headers
To verify if the security headers have been applied successfully, follow these steps:
For the Manual Approach
- Open the developer tools in your browser.
- Go to the network tab.
- Refresh the page.
- Click on the document's HTML (typically it's the first one listed) and check in the headers section for the headers you've specified. Please note: This step may vary slightly depending on the browser and its version.
For the Automatic Approach
- Open the inspector in your browser.
- Go to the
<head>
tag and expand it. - Check for a
<meta
> tag that should look something like this:
<meta http-equiv="Content-Security-Policy" content="frame-src 'self'; img-src 'self'; style-src 'self' 'sha256-rMnTUSuxgLddcNlMSx4iCGs5b7ce4g8N27D0OT00AXo=' 'sha256-7wa/lRg6rKXJI6ZdZTVoeayrZYcjHExhkuhlWqZpGrM='; script-src 'self' 'sha256-DpWm0UmsKLVi7t7KXl0EdDnMX7J663y1fPVnT5+8pLI='">
Tools to Test Security Headers
To ensure the strength of your CSP, you can utilize the following tools:
- CSP Evaluator: Paste your CSP into the CSP Evaluator tool to receive recommendations for you can improve it.
- Security Headers: After deploying your project on Netlify, use Security Headers by Probely to identify any missing security headers or evaluate your current setup.
Netlify plugin for setting CSP
If you usually host your projects on Netlify, you can now easily set up your Content Security Policy by enabling the CSP plugin from your project's dashboard. This integration sets a dynamic CSP in combination with a nonce through an edge function helping you increase your website's security. Make sure to read the documentation to correctly configure it. The best part is that it's SSG agnostic—I enabled the CSP integration on several Jekyll and Next.js projects more than a month ago and I’ve encountered no inconvenience so far.
Conclusion
Establishing good security practices early on is important for front-end developers. By setting security headers, you can protect your projects from potential threats. That's why encourage you to delve deeper into this topic, continuously learn, and stay updated with evolving security measures to ensure the safety of your websites and users.
Liked this article? Share it on: