CSP Security: 10 Best Content Security Policies
Updated on Feb 5th, 2025
From small startups to massive conglomerates, every organization faces the risk of cyberattacks. Although security measures have improved, hackers continuously find new methods to bypass them. One of the most common ways hackers access a site or network is by taking advantage of weak content security policies and injecting their malicious code into it through existing content. That’s why organizations should carefully consider their CSP security strategy.
Statistics suggest that close to 40% of cyberattacks targeting large US and European companies in 2019 used cross-scripting, a form of attack that exploits content security vulnerabilities. Organizations have turned to strict content security policy measures to help mitigate the problem in the past. But cybercriminals are quickly outpacing this solution.
What Is Content Security Policy (CSP), and How Does It Work?
Content Security Policy (CSP) is a computer security standard that has been in use since 2004. This veteran technique aims to combat code injection attacks such as cross-site scripting (XSS) and clickjacking, which target website areas where users can add content (such as checkout pages).
While CSP can help protect against these attacks, it requires adding a CSP HTTP header into the webpage and assigning specific values to control the resources users add to it, including pictures, videos, and forms. Delineating specific values to all incoming content makes it harder for attackers to inject code into your websites through user uploads.
CSPs allow you to restrict the content your users can upload to the site through directives in the HTTP response header or via specific page-level directives through HTML meta tags. To be effective, a CSP needs to be well planned. CSPs are directives that guide which resources (images, fonts, multimedia, and especially scripts) the user must add to ensure that their browsing environment remains secure.
CSP Security: 10 Most Commonly Used CSPs
CSPs can vary, and what makes one policy better than another can depend on your site’s specific needs. We’ve collected our top eight recommendations for 2022 for you to pick and choose what may work best with your existing CSP, your other cybersecurity policies, and, most importantly, your organization’s unique needs.
1: Basic CSP Policy
This basic policy limits the resources used in the default directives to resources from the originating domain and prevents inline scripts/styles execution. That’s how this policy contains cross-site framing and cross-site form submission. In other words: These restrictions reduce your site’s attack surface, making it more secure. This policy can be applied to most modern browsers.
The most basic policy assumes:
- There aren’t any form submissions to external websites
- Other websites aren’t needed to frame the website
- The same domain hosts all resources as the document
- There aren’t any inlines or evals for scripts and style resources
The basic policy:
Content-Security-Policy: default-src ‘self’; frame-ancestors ‘self’; form-action ‘self’;
This can be made more secure by applying:
Content-Security-Policy: default-src ‘none’; script-src ‘self’; connect-src ‘self’; img-src ‘self’; style-src ‘self’; frame-ancestors ‘self’; form-action ‘self’;
This only allows the content of the same origin to be added.
2: Basic CSP Policy – upgrade-insecure-requests
This directive is for developers migrating from HTTP to HTTPS. It ensures that all of a site’s insecure URLs served over HTTP are treated as though they have been replaced with secure URLs (served over HTTPS). This policy is designed for websites with many insecure legacy URLs, which must now be converted to secure URLs.
Content-Security-Policy: upgrade-insecure-requests;
3: Basic CSP Policy to Prevent Framing Attacks
Framing attacks such as clickjacking and cross-site leaks rely on leveraging vulnerabilities in the site to slip in third-party outsider content. For example, clickjacking hides the malicious code and tricks users into clicking an element disguised as another. Implementing a CSP policy to prevent these attacks can be done with the following directives:
- To forbid all framing of your content:
Content-Security-Policy: frame-ancestors ‘none’; - To allow framing for the site itself:
Content-Security-Policy: frame-ancestors’ self’; - To allow framing from trusted domains:
Content-Security-Policy: frame-ancestors trusted.com;
Forbidding all frame-ancestors prevents any page framing, making attacks such as clickjacking impossible. Like all CSP directives, this directive can be customized to allow specific origins, such as framing from self or the same origin.
4: Strict Policy
A strict content security policy is based on nonces or hashes. Using a strict CSP prevents hackers from using HTML injection flaws to force the browser to execute the malicious script. The policy is especially effective against classical stored, reflected, and various DOM XSS attacks.
While all these are XSS attacks, there are slight variations. DOM-based XSS processes data that originates from an untrusted source by writing the data to a possibly dangerous sink within the DOM. Reflected XSS occurs when a site or application receives data in an HTTP request, including data within the immediate response in an insecure way. Finally, stored XSS injects code into the server, where user input is usually stored. This type of attack can only be leveled against sites that store user data, such as message boards. Strict content security policies can prevent all these attacks.
A strict policy can be applied at the following two levels:
- Moderate Strict Policy:
script-src ‘nonce-r4nd0m’ ‘strict-dynamic’;
object-src ‘none’; base-uri ‘none’; - Locked Down Strict Policy:
script-src ‘nonce-r4nd0m’;
object-src ‘none’; base-uri ‘none’;
CSP Security: What is a Nonce?
A nonce (short for “number used once”) is a unique, random value generated for each request. When a strict CSP is applied with a nonce, only scripts that include the correct nonce value are allowed to execute. This prevents unauthorized inline scripts from running, even if an attacker injects malicious JavaScript into the page.
For example:
script-src ‘nonce-r4nd0m’;
- The browser will only execute scripts that have the matching ‘nonce-r4nd0m’.
- Even if an attacker injects a <script> tag, it won’t run unless it has the correct nonce, which is generated dynamically and changes with every page load.
By implementing nonces, you can remove ‘unsafe-inline’ from your CSP, significantly enhancing your site’s security posture.
5: Refactoring Inline Code
When the default default-src or script-src directives are active, the security policy disables any JavaScript code placed inline in the HTML by default. For example:
<script> var num = "20" <script>
The inline code is moved to a separate JavaScript file and the page’s code becomes:
<script src="app.js"> </script>
The app.js now contains the var num = “20” code.
The inline code restriction also applies to inline event handlers, making the following construct blocked under the CSP:
<button id="button1" onclick="doSomething()">
This must be replaced by addEventListener calls:
document.getElementById("button1").addEventListener('click', doSomething);
6: CSP with Fetch Directives
Fetch directives control the locations from which specific resources can be loaded, telling the browser which sources to trust. When it comes to CSPs, fetch directives allow you to control the location from which resources can be loaded from, preventing foreign and malicious resources from infiltrating your site.
Directives such as script-src give developers the ability to allow trusted sources of script to execute on the page, font-src delineates the source of web fonts, and child-src allows developers to control nested browsing contexts and worker execution contexts. In addition, the directives allow developers to limit the source of content that can access the site, preventing attackers from adding malicious code. A directive is always needed, so if one isn’t added to the CSP header, the system will automatically fall back on the default-src.
7: CSP with Document Directives
Document directives inform the browser which properties of the document the content security policies apply to. For example, by restricting URLs that can be used as the document’s element:
Content-Security-Policy: base-uri <source>;
Content-Security-Policy: base-uri <source> <source>;
Or by enabling a sandbox for the requested resource:
Content-Security-Policy: sandbox;
Content-Security-Policy: sandbox <value>;
8: CSP with Navigation Directives
Navigation directives restrict the URLs to which a document can navigate or submit forms. In turn, navigation directive policies control what location users can navigate or submit forms to. Navigation directives don’t revert to default-src directives and instead include directives such as:
- Restricting URLs forms can be submitted to:
Content-Security-Policy: form-action <source>;
Content-Security-Policy: form-action <source> <source>; - The URL a document can initiate navigation to:
Content-Security-Policy: navigate-to <source>;
Content-Security-Policy: navigate-to <source> <source>;
9: CSP with Worker Directives
Worker directives manage the sources from which web workers and shared workers can be loaded. This helps ensure that only trusted scripts can execute in worker threads, reducing the risk of malicious background processes.
Restricting web worker sources:
Content-Security-Policy: worker-src <source>;
Content-Security-Policy: worker-src <source> <source>;
10: CSP with Sandbox Directives
Sandbox directives apply security restrictions to iframes, similar to the sandbox attribute in HTML. These restrictions limit the iframe’s capabilities, such as running scripts, submitting forms, or navigating the top-level page.
Applying sandbox restrictions:
Content-Security-Policy: sandbox;
Content-Security-Policy: sandbox allow-scripts allow-forms;
Bonus CSP
11: CSP with Form Submission Directives
Form submission directives restrict the URLs where forms can send data. This helps prevent malicious actors from intercepting sensitive user input by ensuring that form submissions are only allowed to trusted sources. Unlike other directives, form-action does not fall back to default-src.
Restricting URLs forms can be submitted to:
Content-Security-Policy: form-action <source>;
Content-Security-Policy: form-action <source> <source>;
CSP Security: Taking Your Security Policies to the Next Level
Each CSP has its pros and cons. Knowing which CSP will work best for your organization may require some trial and error, which is why CSP testing is an indispensable part of the process. As CSPs play a critical role in controlling content sources and page behavior, a single error may make your page entirely inaccessible to visitors. Testing your CSP before implementation enables you to see if it meets your organization’s needs (and avoid costly or embarrassing errors).
Despite their benefits, CSPs are not the right solution for everyone. While CSPs can help prevent malicious code injection, attack methods have evolved beyond the limited protection CSPs can offer. Although CSPs are generally effective, it’s best not to rely on a CSP as a standalone solution. Instead, combine it with other security measures such as SRI, discovery tools, and validation tests. To learn more about website security and other solutions you can implement with your CSP, check out Reflectiz free trial here.
FAQs
How does CSP protect against clickjacking and framing attacks?
CSP protects against clickjacking and other framing attacks using the frame-ancestors directive, which controls which origins are permitted to embed the page in an iframe, frame, or object. Setting frame-ancestors ‘none’ prevents any website from embedding the page — making clickjacking attacks impossible, since they rely on overlaying the victim page inside an invisible iframe to trick users into clicking disguised elements. Setting frame-ancestors ‘self’ permits only the same origin to embed the page, while frame-ancestors trusted.com allows specific trusted domains. Cross-site leak attacks, which exploit framing to infer sensitive information about user state across origins, are similarly mitigated. Unlike the older X-Frame-Options header, the CSP frame-ancestors directive offers more granular control and is the recommended modern approach to framing protection.
Is a Content Security Policy enough on its own to secure a website?
No — a Content Security Policy is an important layer of defense but should not be treated as a standalone security solution. CSPs are effective at restricting which resources the browser can load and preventing many categories of code injection, but attack methods have evolved beyond what CSPs alone can block. A poorly configured CSP can still leave significant gaps, and a misconfigured one can make the site inaccessible to legitimate visitors. Additionally, CSPs provide no protection against server-side vulnerabilities, supply chain attacks that compromise trusted script sources, or behavioral changes in already-approved third-party scripts. Security practitioners recommend combining CSP with complementary controls including Subresource Integrity (SRI) for verifying the integrity of third-party resources, continuous script monitoring and discovery tools to detect unauthorized changes, and regular validation testing to ensure the policy is enforced correctly across all browsers and environments.
What are CSP fetch directives and how do they control resource loading?
CSP fetch directives tell the browser which external sources are trusted to load specific types of resources. Each directive targets a different resource type: script-src controls JavaScript sources, style-src controls CSS, img-src controls images, font-src controls web fonts, and child-src governs nested browsing contexts (iframes) and web workers. If a specific directive is not defined in the CSP header, the browser falls back to the value set in default-src, ensuring a baseline restriction is always applied. Together, fetch directives form the core of a CSP’s resource control layer — by restricting scripts, images, and fonts to trusted origins only, they prevent attackers from loading malicious external resources or injecting unauthorized code into the page.
What are CSP navigation directives and what do they restrict?
CSP navigation directives restrict where a document can send users and data, closing off attack vectors that bypass standard resource-loading controls. Unlike fetch directives, navigation directives do not fall back to default-src — they must be explicitly defined. The two primary navigation directives are:
form-action: Restricts the URLs that HTML forms on the page can submit data to. This prevents attackers from redirecting form submissions (including login forms and payment forms) to attacker-controlled servers. For example: Content-Security-Policy: form-action ‘self’;
navigate-to: Restricts the URLs the document can navigate to via links, redirects, or window.location changes. Together, these directives prevent open redirect attacks and unauthorized data exfiltration through form submissions, helping ensure that users and their data can only be sent to explicitly trusted destinations.
What does the CSP upgrade-insecure-requests directive do?
The upgrade-insecure-requests CSP directive instructs the browser to automatically treat all HTTP URLs on the page as HTTPS, rewriting them before the request is made. It is specifically designed for websites that are migrating from HTTP to HTTPS and have large numbers of legacy insecure URLs embedded in their markup, styles, or scripts. Rather than manually updating every link, image source, and resource reference, developers can deploy a single directive to ensure all content is requested over a secure, encrypted connection:
Content-Security-Policy: upgrade-insecure-requests;
This directive helps prevent mixed content warnings (where an HTTPS page loads HTTP resources), protects against passive network attackers who could intercept unencrypted resources, and is particularly useful during phased HTTPS migrations where not all references have yet been updated to HTTPS.
What is a CSP nonce and why is it important for security?
A CSP nonce (short for “number used once”) is a unique, cryptographically random value generated server-side for every page request and embedded in both the Content-Security-Policy header and any legitimate inline script tags. The browser will only execute inline scripts that carry the matching nonce value — so even if an attacker successfully injects a malicious <script> tag into the page, it will not run because it lacks the correct nonce. Because nonces are dynamically generated and change with every page load, they cannot be predicted or reused by attackers. Using nonces in a strict CSP allows developers to eliminate the insecure ‘unsafe-inline’ directive while still supporting necessary inline scripts, significantly raising the bar against XSS attacks including stored, reflected, and DOM-based variants.
What is a strict Content Security Policy and when should you use it?
A strict Content Security Policy is a CSP configuration based on cryptographic nonces or hashes rather than origin allowlists. It is the most effective CSP approach for preventing XSS attacks because it blocks all inline scripts that do not carry a valid nonce or hash — including those injected by attackers via HTML injection flaws. A strict CSP defends against all three major categories of XSS: stored XSS (injected into server-stored content), reflected XSS (injected via HTTP request parameters), and DOM-based XSS (injected through client-side script execution). It comes in two levels: a moderate strict policy that uses nonces with strict-dynamic to trust scripts loaded by trusted scripts, and a fully locked-down policy that allows only nonce-matched scripts. Organizations handling sensitive user data, payment information, or regulated personal data should prioritize implementing a strict CSP.
What is Content Security Policy (CSP) and how does it work?
Content Security Policy (CSP) is a browser security standard introduced in 2004 that helps defend websites against code injection attacks such as cross-site scripting (XSS) and clickjacking. It works by allowing website owners to specify, via an HTTP response header or HTML meta tag, exactly which sources of content — scripts, stylesheets, images, fonts, and other resources — the browser is permitted to load and execute. Any resource from an unlisted source is blocked by the browser before it can run. By defining a strict allowlist of trusted origins for each content type, CSP significantly reduces the attack surface available to attackers who rely on injecting malicious code through user-facing areas of a website, such as comment fields or checkout pages.
What is the most basic CSP configuration and what does it protect against?
The most basic Content Security Policy restricts all resources to the same origin as the document and disables inline scripts and styles. It is expressed as:
Content-Security-Policy: default-src ‘self’; frame-ancestors ‘self’; form-action ‘self’;
This policy assumes that all resources (images, scripts, stylesheets) are hosted on the same domain, there are no external form submissions, and no inline or eval-based JavaScript is used. It protects against cross-site framing attacks, cross-site form submissions, and basic XSS via external script injection. A stricter variant — using default-src ‘none’ and explicitly allowlisting only the required resource types — further tightens the attack surface by blocking everything by default and only permitting what is explicitly needed.
Why is CSP testing important before deploying a content security policy?
CSP testing before deployment is critical because a single error in a content security policy can make an entire website inaccessible to visitors — blocking legitimate scripts, stylesheets, or resources that the site depends on. CSPs govern which content sources the browser will load, so an overly restrictive or incorrectly configured policy can break site functionality, block third-party integrations, or prevent analytics and payment systems from operating. Testing allows developers to validate that the policy correctly allows all required resources while blocking unauthorized ones. The recommended approach is to first deploy the policy in report-only mode using the Content-Security-Policy-Report-Only header, which logs violations without enforcing them. This reveals which resources would be blocked under the policy without causing user-facing disruption, enabling teams to refine the policy before switching to full enforcement mode.
Subscribe to our newsletter
Stay updated with the latest news, articles, and insights from Reflectiz.
Your Website looks great!
But what’s happening behind the scenes?
Discover your website blind spots and vulnerabilities before it’s too late!