Modern websites rely on JavaScript, APIs, CDNs, and third-party services, which can increase security risks. Content Security Policy (CSP) helps control these risks by restricting which resources a website can load and execute.
Content Security Policy (CSP): A Practical Guide to Securing Your Website
Modern websites depend on JavaScript, CSS, images, fonts, APIs, analytics platforms, CDNs, and other third-party services. While these technologies improve functionality and user experience, they can also increase the attack surface of a web application.
One important security mechanism that helps control this risk is Content Security Policy (CSP).
Content Security Policy is a browser security mechanism that allows website administrators to define which sources are trusted for loading and executing content. When properly configured, CSP can reduce the impact of attacks such as **Cross-Site Scripting (XSS)** and certain types of content injection.
In this guide, we will understand what CSP is, how it works, important directives, common mistakes, implementation methods, and how CSP can be assessed during a VAPT.
What Is Content Security Policy?
Content Security Policy is implemented through an HTTP response header.
A basic example is:
Content-Security-Policy: default-src 'self';
This tells the browser to use the website's own origin as the default trusted source for resources.
A more specific policy can control individual resource types:
Content-Security-Policy: default-src 'self'; script-src 'self';
Here, the policy establishes a default restriction and limits JavaScript to the website's own origin.
CSP does not replace secure application development. Instead, it provides an additional browser-side security layer.
---
Why Is CSP Important?
One of the major benefits of CSP is reducing the impact of certain XSS attacks.
For example, imagine an application contains an input-validation vulnerability that allows an attacker to inject:alert('XSS')
If the application's CSP prevents unauthorized inline scripts or untrusted script sources from executing, the browser may block the injected code.
This does not mean the underlying XSS vulnerability has been fixed. Developers should still perform proper input validation and output encoding.
Therefore, CSP should be considered **defense in depth** rather than a replacement for secure coding.
---
How Does CSP Work?
When a user visits a website, the server sends an HTTP response containing headers.
For example:
Content-Security-Policy: default-src 'self';
The browser reads this policy and applies the defined restrictions when loading resources.
A policy might specify that:
- *JavaScript can only come from trusted domains.
- *Images can come from specific locations.
- *Fonts can be loaded from an approved CDN.
- *API requests can connect only to trusted endpoints.
- *Objects and plugins are completely disabled.
- *The website cannot be embedded by unauthorized websites.
This gives the website owner greater control over what the browser is allowed to load or execute.
---
Important CSP Directives
CSP contains many directives. The following are commonly used when securing modern web applications.
1. default-src
`default-src` provides a fallback policy for resource types that do not have their own specific directive.
Example:
Content-Security-Policy: default-src 'self';
It provides a useful restrictive baseline.
---
2. script-src
Controls where JavaScript can be loaded from.
script-src 'self' https://cdn.example.com;
This allows scripts from the same origin and the specified trusted CDN.
Avoid unnecessarily using:
'unsafe-inline'
or:
'unsafe-eval'
because these can weaken the protection provided by CSP.
---
3. style-src
Controls where CSS can be loaded from.
style-src 'self' https://fonts.googleapis.com;
If the application uses inline styles, the policy may need to accommodate them using an appropriate mechanism.
---
4. img-src
Controls permitted image sources.
img-src 'self' data: https:;
However, broad source allowances should be used carefully. Only allow sources that the application actually requires.
---
5. font-src
Controls the sources from which fonts can be loaded.
font-src 'self' https://fonts.gstatic.com;
This is commonly required when websites use external font providers.
---
6. connect-src
Controls network connections initiated by browser-side scripts, including Fetch, AJAX, WebSocket, and similar connections.
connect-src 'self' https://api.example.com;
This is particularly important for applications that communicate with external APIs.
---
7. frame-src
Controls the sources that can be loaded inside frames.
frame-src 'self' https://www.youtube.com;
This can be useful when embedding trusted third-party services.
---
8. object-src
Controls embedded objects and legacy plugins.
A restrictive configuration is:
object-src 'none';
If the application does not require such content, disabling it reduces unnecessary exposure.
---
9. base-uri
Controls the URLs that can be used in the HTML `` element.
base-uri 'self';
This can help prevent unwanted manipulation of the document's base URL.
---
10. frame-ancestors
Controls which websites can embed your page.
frame-ancestors 'self';
This can help protect against certain clickjacking scenarios.
---
Understanding 'unsafe-inline'
One of the most frequently encountered CSP settings is:
script-src 'self' 'unsafe-inline';
The `'unsafe-inline'` keyword permits inline script execution in contexts governed by the directive.
Although it may be convenient for applications that depend on inline JavaScript, it can reduce CSP's protection against certain script injection attacks.
Where practical, applications should move toward **nonces or hashes** instead of broadly permitting inline scripts.
---
CSP Nonces and Hashes
A nonce is a random value generated for an appropriate response and used to authorize specific inline scripts.
For example:
Content-Security-Policy: script-src 'self' 'nonce-randomValue';
The corresponding script can contain:
console.log("Trusted script");
The nonce should be unpredictable and handled securely.
Another approach is a **CSP hash**, where the policy contains a cryptographic hash corresponding to an approved inline script.
These mechanisms provide more granular control than allowing all inline scripts.
---
Report-Only CSP
Deploying a strict CSP immediately can sometimes break legitimate website functionality.
For testing, administrators can use:
Content-Security-Policy-Report-Only: default-src 'self';
Report-Only mode allows the team to identify policy violations before enforcing the policy.
A practical implementation process is:
**Develop → Test → Monitor → Adjust → Enforce**
This is especially useful for websites that depend on multiple third-party services.
---
Common CSP Mistakes
Overly Broad Policies
A policy such as:
script-src *;
allows scripts from a very broad range of sources and reduces the effectiveness of CSP.
Excessive Use of 'unsafe-inline'
Allowing all inline scripts can weaken protection against certain XSS scenarios.
Unnecessary 'unsafe-eval'
This should not be enabled unless the application's requirements genuinely demand it.
Trusting Too Many Domains
Every additional trusted domain increases the number of sources the browser is instructed to trust.
Only include domains that are actually required.
Copying Another Website's CSP
There is no universal CSP that works for every application.
A policy should be designed around the website's actual scripts, APIs, fonts, images, CDNs, and third-party integrations.
---
How to Test CSP
CSP can be reviewed using browser developer tools and command-line utilities.
Browser Developer Tools
Open Chrome or Firefox Developer Tools and inspect:
Network → Response Headers
Look for:
Content-Security-Policy
The browser Console can also show CSP violations, such as blocked scripts or resources.
These messages can help identify legitimate resources that are missing from the policy.
Using cURL
You can inspect HTTP response headers with:
curl -i https://example.com
To search specifically for CSP:
curl -I https://example.com | grep -i content-security-policy
If CSP is configured, the response should contain the corresponding header.
Security-header scanning tools can also help identify missing or potentially weak security headers. However, automated scanners should be treated as a starting point rather than a complete security assessment.
---
Implementing CSP Using .htaccess
For Apache servers, CSP can be configured using `mod_headers`.
For example:
Header always set Content-Security-Policy "default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self';"
Before modifying `.htaccess`, it is important to:
- 1. Create a backup.
- 2. Confirm the required Apache module is available.
- 3. Make one change at a time.
- 4. Test the website after each change.
- 5. Check the browser Console for CSP violations.
- 6. Test forms, APIs, scripts, images, fonts, and third-party integrations.
- 7. Monitor for unexpected resource blocking.
A syntax error in `.htaccess` can result in an **HTTP 500 Internal Server Error**, so configuration changes should be performed carefully.
---
CSP During a VAPT Assessment
Content Security Policy can be reviewed as part of a web application VAPT.
A security tester can check:
- *Whether CSP is implemented.
- *Whether it is enforced or Report-Only.
- *Whether `default-src` is configured.
- *Whether scripts are allowed from unnecessarily broad sources.
- *Whether `'unsafe-inline'` is used.
- *Whether `'unsafe-eval'` is used.
- *Whether `object-src` is restricted.
- *Whether `base-uri` is restricted.
- *Whether `frame-ancestors` is configured.
- *Whether unnecessary third-party domains are trusted.
- *Whether browser Console messages reveal policy violations.
The assessment should consider the application's actual functionality. A CSP should not be judged solely on the number of directives it contains.
---
Recommended CSP Hardening Approach
A practical CSP implementation can follow these steps.
Step 1: Identify Required Resources
Document the JavaScript, CSS, images, fonts, APIs, frames, CDNs, and third-party services used by the application.
Step 2: Create a Baseline
Start with a restrictive policy such as:
default-src 'self';
Then add only the sources required by the application.
Step 3: Restrict High-Risk Content
Where appropriate, consider:
object-src 'none';
base-uri 'self';
and configure `frame-ancestors` according to the application's requirements.
Step 4: Avoid Unnecessary Weakening
Remove unnecessary `'unsafe-inline'` and `'unsafe-eval'` allowances where the application supports safer alternatives.
Step 5: Test Using Report-Only
Monitor violations and identify legitimate resources before enforcement.
Step 6: Enforce the Final Policy
Once the policy has been tested and validated, deploy it as an enforced `Content-Security-Policy` header.
---
Conclusion
Content Security Policy is an important layer of modern web application security. A properly designed CSP can restrict unauthorized resource loading and reduce the impact of certain XSS and content-injection attacks.
However, CSP should not be treated as a standalone security solution.
A secure web application should combine CSP with secure coding, input validation, output encoding, authentication, access control, HTTPS, secure cookies, dependency management, vulnerability assessments, and continuous monitoring.
The goal of CSP is not to create the longest possible security header. The goal is to create a policy that allows only the resources the application genuinely needs and restricts everything else.
For cybersecurity professionals performing VAPT assessments, understanding CSP is valuable because it provides insight into how an application controls browser-side resources and implements defense-in-depth against web-based attacks.
Need Help Securing Your Website?
Protect your website with the right security controls, configurations, and vulnerability assessments. **Contact Innoway Technology** for professional website security and cybersecurity requirements.
Visit {https://www.innoway.co.in/} to discuss your security needs and get the right solution for your website.


