Security Headers Checklist
A practical checklist of HTTP security headers for modern web applications, including CSP, HSTS, Referrer-Policy, Permissions-Policy, and browser security controls.
HTTP security headers are response headers that tell browsers how a website should handle potentially dangerous behavior. They can restrict where resources are loaded from, control whether a site may be embedded by another page, reduce information leaked through the Referer header, enforce HTTPS, and limit access to browser capabilities.
Security headers do not replace secure application code, authentication, authorization, input validation, dependency updates, or other security controls. Instead, they add browser-enforced restrictions that can reduce the impact of certain vulnerabilities and make common attacks more difficult.
This checklist focuses on the headers that are most relevant to modern web applications. The correct configuration depends on the application's resources, APIs, authentication model, embedding requirements, and browser features.
Security Headers Checklist at a Glance
| Header | Main purpose | Typical recommendation |
|---|---|---|
| Content-Security-Policy | Restricts where browser resources can come from | Configure explicitly for the application |
| Strict-Transport-Security | Tells browsers to use HTTPS | Use on HTTPS sites after verifying HTTPS readiness |
| X-Content-Type-Options | Prevents MIME type sniffing | Set to nosniff |
| Referrer-Policy | Controls Referer information sent with requests | Choose a policy appropriate for the application |
| Permissions-Policy | Controls access to selected browser features | Restrict unnecessary features |
| X-Frame-Options | Controls whether pages may be framed | Useful for compatibility with older clients |
| frame-ancestors in CSP | Controls which sites may embed a page | Prefer for modern CSP-based control |
| Cross-Origin-Opener-Policy | Controls browsing-context relationships | Consider for applications needing isolation |
| Cross-Origin-Resource-Policy | Controls cross-origin resource loading | Use when resource sharing requirements are understood |
| Cross-Origin-Embedder-Policy | Controls cross-origin resource embedding | Use when cross-origin isolation is required |
1. Content-Security-Policy
Content-Security-Policy, usually abbreviated as CSP, is one of the most important security headers for modern web applications. It allows a site to specify which sources the browser is permitted to use for scripts, styles, images, fonts, frames, connections, and other resource types.
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self';A restrictive CSP can reduce the impact of some cross-site scripting vulnerabilities because injected scripts may be blocked even when malicious markup reaches the page. However, CSP is a defense-in-depth mechanism rather than a replacement for output encoding and other XSS defenses.
Important CSP Directives
| Directive | Controls |
|---|---|
| default-src | Fallback policy for many resource types |
| script-src | JavaScript sources |
| style-src | Stylesheet sources |
| img-src | Image sources |
| font-src | Font sources |
| connect-src | Fetch, XHR, WebSocket, and similar connections |
| media-src | Audio and video sources |
| frame-src | Sources that may be embedded in frames |
| frame-ancestors | Which origins may embed the page |
| object-src | Plugin-style object resources |
| base-uri | Allowed base element URLs |
| form-action | Where forms may submit |
| worker-src | Worker and service-worker sources |
A common mistake is copying a CSP from another project without understanding the application's dependencies. Third-party analytics, payment providers, CDNs, fonts, APIs, images, and embedded services may require additional sources.
Avoid an Overly Permissive CSP
Content-Security-Policy: default-src * 'unsafe-inline' 'unsafe-eval';Policies that allow arbitrary origins or broadly permit inline and dynamically evaluated code can significantly reduce the protection CSP is intended to provide. A good policy should allow the resources the application actually needs rather than everything a browser could load.
CSP Report-Only
CSP can also be deployed in report-only mode while a policy is being tested. A report-only policy lets developers observe violations without immediately blocking the corresponding resources.
Content-Security-Policy-Report-Only: default-src 'self'; script-src 'self';This is useful for discovering legitimate dependencies before enforcing a policy. Once the policy has been tested and adjusted, the application can move to an enforcing Content-Security-Policy header.
2. Strict-Transport-Security
Strict-Transport-Security, or HSTS, tells a browser that a website should be accessed using HTTPS for a specified period. It helps prevent certain downgrade and accidental HTTP access scenarios after the browser has received the policy over a secure connection.
Strict-Transport-Security: max-age=31536000; includeSubDomainsThe max-age directive specifies how long the browser should remember the policy. includeSubDomains extends the policy to subdomains.
HSTS Preload
HSTS preload is a separate mechanism in which a domain is included in browser-maintained preload lists. This can allow browsers to treat the domain as HTTPS-only even before receiving an HSTS response.
Preloading should be treated as a deliberate operational decision. Domains need to satisfy the applicable requirements, and all relevant subdomains must be prepared for HTTPS-only behavior if the configuration requires it.
3. X-Content-Type-Options
X-Content-Type-Options controls whether browsers may perform MIME type sniffing in situations where the declared Content-Type does not clearly determine how a resource should be interpreted.
X-Content-Type-Options: nosniffThe nosniff value is the standard value used for this header. It helps prevent browsers from interpreting resources as a different type than the server declared.
Correct Content-Type Still Matters
X-Content-Type-Options does not fix incorrect MIME types. Servers should still return the correct Content-Type for JavaScript, CSS, images, fonts, JSON, downloads, and other resources.
Content-Type: application/javascript
X-Content-Type-Options: nosniff4. Referrer-Policy
Referrer-Policy controls how much information about the page that initiated a request is included in the Referer request header.
Referrer-Policy: strict-origin-when-cross-originstrict-origin-when-cross-origin is a commonly used modern policy. It can send the full URL for same-origin requests while limiting cross-origin requests to the origin in relevant cases.
| Policy | General behavior |
|---|---|
| no-referrer | Sends no referrer information |
| same-origin | Sends referrer information to same-origin destinations |
| strict-origin | Sends only the origin when allowed by the security context |
| strict-origin-when-cross-origin | Provides more detail same-origin and limits information cross-origin |
| origin | Sends only the origin |
The correct policy depends on whether the application relies on referrer information for analytics or integrations and whether URLs could contain sensitive information. Sensitive values should not be placed in URLs in the first place.
5. Permissions-Policy
Permissions-Policy controls whether a page and selected embedded frames may use certain browser features. Depending on browser support, policies can restrict capabilities such as camera, microphone, geolocation, fullscreen, payment, and other features.
Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()If an application does not need a powerful browser feature, restricting it can reduce the number of capabilities available to pages and embedded content.
Permissions-Policy syntax and browser support vary by feature, so the policy should be tested against the actual functionality used by the application.
6. X-Frame-Options
X-Frame-Options controls whether a page can be displayed inside a frame. It is primarily associated with protection against clickjacking.
X-Frame-Options: DENYDENY prevents the page from being framed. SAMEORIGIN permits framing by the same origin.
For modern applications, CSP's frame-ancestors directive provides more flexible framing control. X-Frame-Options can still be useful for compatibility with older clients and security tooling.
7. CSP frame-ancestors
The frame-ancestors CSP directive specifies which origins are allowed to embed the protected page in a frame.
Content-Security-Policy: frame-ancestors 'self'Using frame-ancestors is generally preferable when an application needs more precise framing rules than X-Frame-Options provides.
8. Cross-Origin-Opener-Policy
Cross-Origin-Opener-Policy, or COOP, controls the relationship between a document and browsing contexts opened from it when those contexts have different origins.
Cross-Origin-Opener-Policy: same-originCOOP can help isolate a document from cross-origin windows. It is particularly relevant when an application requires stronger browsing-context isolation or wants to participate in cross-origin isolation.
9. Cross-Origin-Resource-Policy
Cross-Origin-Resource-Policy, or CORP, controls which origins may load a resource in certain cross-origin contexts.
Cross-Origin-Resource-Policy: same-originThe available policies include same-origin, same-site, and cross-origin. The appropriate value depends on whether resources such as images, scripts, fonts, or other files are intentionally consumed by other origins.
10. Cross-Origin-Embedder-Policy
Cross-Origin-Embedder-Policy, or COEP, controls whether a document can load certain cross-origin resources unless those resources explicitly permit being loaded in that context.
Cross-Origin-Embedder-Policy: require-corpCOEP is particularly relevant when an application wants cross-origin isolation together with COOP. However, enabling it can break third-party resources that do not provide the required cross-origin permissions.
Cross-Origin Isolation
COOP and COEP can be used together to create a cross-origin isolated browsing context. Cross-origin isolation is required by some browser capabilities and can change how cross-origin resources and windows interact with the application.
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corpThese headers should not be enabled just because they appear on a generic security checklist. They are most useful when the application's requirements justify cross-origin isolation.
Headers That Should Not Be Copied Blindly
Security headers are not universal configuration snippets. A value that is appropriate for one application can break another application or provide little useful protection.
| Header | Potential issue when misconfigured |
|---|---|
| Content-Security-Policy | Scripts, styles, APIs, fonts, or third-party services may stop working |
| Strict-Transport-Security | HTTP-only subdomains may become inaccessible |
| Permissions-Policy | Required browser features may stop working |
| X-Frame-Options | Legitimate embedding may be blocked |
| Cross-Origin-Opener-Policy | Popup and cross-origin window integrations may change behavior |
| Cross-Origin-Embedder-Policy | Third-party resources may fail to load |
| Cross-Origin-Resource-Policy | Resources may become unavailable to intended origins |
A Practical Baseline
A simple HTTPS application can start with a small baseline and then add more restrictive policies after testing. The following example is illustrative rather than a universal copy-and-paste configuration.
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
X-Frame-Options: DENY
Permissions-Policy: camera=(), microphone=(), geolocation=()
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'The CSP in this example is intentionally small. Real applications commonly need additional directives for JavaScript, styles, images, fonts, API connections, frames, and third-party services.
Headers and Cookies Work Together
Security headers do not replace secure cookie configuration. Applications using session cookies should also consider attributes such as Secure, HttpOnly, and an appropriate SameSite setting.
Set-Cookie: session=...; Secure; HttpOnly; SameSite=LaxSecure ensures the cookie is sent over HTTPS, HttpOnly prevents normal JavaScript access to the cookie, and SameSite controls when cookies are included in cross-site requests. The appropriate SameSite value depends on the authentication and application flow.
Security Headers Do Not Fix XSS
CSP can reduce the impact of some XSS vulnerabilities, but it does not make unsafe HTML rendering safe by itself. Applications should still perform context-appropriate output encoding, safely handle user-controlled HTML, validate input where appropriate, and use secure framework APIs.
A restrictive CSP is best treated as an additional layer. If an application has an injection vulnerability, the underlying vulnerability should still be fixed.
Security Headers and CORS Are Different
CORS controls which origins are permitted to access resources through browser cross-origin requests. Security headers such as CSP, HSTS, and Permissions-Policy address different browser security behaviors.
For example, CSP's connect-src can restrict which destinations the page itself may contact, while CORS determines whether a browser permits JavaScript from another origin to read a response. These controls can work together but should not be treated as interchangeable.
Do Security Headers Protect APIs?
Some security headers are primarily useful for browser-rendered documents and have limited relevance to API responses consumed by non-browser clients. An API should still use appropriate authentication, authorization, input validation, rate limiting, transport security, and secure response handling.
That said, API responses can still benefit from headers such as X-Content-Type-Options, correct Content-Type values, cache controls where appropriate, and other headers relevant to how the API is consumed.
Caching and Sensitive Responses
Security headers should be considered alongside caching behavior. Pages containing private account information or other sensitive data should not accidentally become publicly cacheable.
Cache-Control: no-storeThe correct caching policy depends on the resource. Public static assets can often be cached aggressively, while authenticated responses may require much more restrictive caching behavior.
How to Test Security Headers
Do not verify security headers only by reading source code. Check the actual HTTP response sent by the production server or deployment platform.
curl -I https://example.comBrowser developer tools can also show response headers in the Network panel. This is especially useful for checking whether redirects, static assets, API routes, and application pages receive the intended headers.
Check More Than the Homepage
A security header configured at the application level may not automatically apply to every resource or response. Reverse proxies, CDNs, static file servers, API routes, redirects, and third-party infrastructure can have separate configuration layers.
- Test the main HTML document.
- Test authenticated pages.
- Test API endpoints where relevant.
- Test redirects.
- Test static assets.
- Test error responses.
- Test pages that use third-party services.
- Test embedded or framed pages if the application supports them.
Security Headers in Next.js
Next.js applications can set response headers through framework configuration, middleware, route handlers, or infrastructure such as a reverse proxy or CDN. The important part is verifying the final response rather than relying only on the configuration file.
const securityHeaders = [
{
key: "X-Content-Type-Options",
value: "nosniff",
},
{
key: "Referrer-Policy",
value: "strict-origin-when-cross-origin",
},
];
export default securityHeaders;The exact implementation depends on the Next.js deployment architecture. CSP may also require dynamic nonces or hashes when an application uses inline scripts, so it should be designed together with the application's rendering strategy.
CSP Nonces and Hashes
A strict CSP does not necessarily require allowing all inline scripts. Nonces and hashes can allow specific inline scripts while keeping the overall policy restrictive.
Content-Security-Policy: script-src 'self' 'nonce-example123'A nonce should be unpredictable and generated for the appropriate response. The server places the same nonce in the CSP and the permitted script element. Hash-based CSP can instead authorize a specific inline script based on its cryptographic hash.
Avoid unsafe-inline When Possible
The unsafe-inline source expression allows inline scripts or styles in contexts controlled by the relevant directive. For scripts, broadly enabling it can significantly weaken the XSS protection provided by CSP.
When practical, use external scripts, nonces, or hashes instead. Some applications may have compatibility constraints that require different decisions, but those decisions should be explicit rather than accidental.
Security Headers Checklist for Production
- Serve the application over HTTPS.
- Configure HSTS only after verifying HTTPS readiness.
- Use X-Content-Type-Options: nosniff.
- Choose an appropriate Referrer-Policy.
- Configure Permissions-Policy for browser features the application does not need.
- Use CSP to restrict resource sources.
- Use frame-ancestors when framing restrictions are required.
- Consider X-Frame-Options for compatibility with older clients.
- Review COOP, COEP, and CORP when cross-origin isolation or resource restrictions are required.
- Configure secure session cookies with appropriate attributes.
- Return accurate Content-Type values.
- Review caching behavior for sensitive responses.
- Test headers on production responses.
- Check redirects and error responses as well as successful pages.
- Review third-party resources before enforcing restrictive policies.
- Monitor CSP violations after deployment.
- Revisit policies when the application's dependencies or browser features change.
Common Security Header Mistakes
- Copying a CSP from another application without adapting it.
- Using a permissive CSP that allows almost every source.
- Enabling HSTS before all required HTTPS endpoints are ready.
- Assuming security headers replace secure application code.
- Using deprecated or obsolete headers without understanding their role.
- Adding COEP or COOP without testing cross-origin integrations.
- Blocking legitimate iframe integrations with overly restrictive framing rules.
- Ignoring third-party scripts and services when designing CSP.
- Checking only the homepage instead of testing different response types.
- Assuming a framework configuration guarantees that every production response contains the header.
- Forgetting that security headers can affect browser behavior and application functionality.
Security Headers vs Application Security
Security headers are one layer in a broader defense-in-depth strategy. A secure application still needs correct authorization, authentication, input handling, output encoding, dependency management, secure session management, rate limiting, logging, monitoring, and safe infrastructure configuration.
For example, CSP may reduce the impact of certain script injection attacks, but it does not determine whether a user is allowed to access another user's account. HSTS helps enforce HTTPS, but it does not make an insecure authorization check safe.
The value of security headers comes from combining browser-level restrictions with secure application design rather than treating headers as a complete security solution.
Frequently Asked Questions
What are security headers?
Security headers are HTTP response headers that tell browsers how to handle certain security-sensitive behaviors. They can control resource loading, HTTPS usage, framing, referrer information, browser features, and cross-origin interactions.
Which security headers should every website use?
There is no single universal set that fits every website. Commonly considered headers include Content-Security-Policy, Strict-Transport-Security for HTTPS sites, X-Content-Type-Options, Referrer-Policy, and Permissions-Policy. Additional cross-origin and framing controls depend on the application's requirements.
Is Content-Security-Policy the most important security header?
CSP is an important browser defense, particularly against some forms of script injection, but its usefulness depends heavily on configuration. It should be combined with secure application code and other security controls.
Can security headers break a website?
Yes. Restrictive policies can block scripts, styles, fonts, API connections, frames, browser features, or third-party resources that the application legitimately needs. Policies should therefore be tested before and after deployment.
Should I use both X-Frame-Options and frame-ancestors?
They address similar framing concerns but have different capabilities and compatibility characteristics. frame-ancestors provides more flexible modern control, while X-Frame-Options can still be useful for compatibility with older clients.
Does HSTS replace HTTPS?
No. HSTS does not provide encryption itself. The website must already support HTTPS correctly. HSTS tells compatible browsers to use HTTPS for future requests according to the policy.
Do security headers protect an API from attacks?
Only some headers have direct relevance to browser-based API consumption. APIs still require authentication, authorization, input validation, rate limiting, secure transport, safe error handling, and other server-side security controls.
Helpful Security Tools
A Security Headers Generator can help create a baseline set of response headers. A CSP Header Builder is useful when constructing and reviewing Content-Security-Policy directives, while an HSTS Header Generator can help formulate Strict-Transport-Security values. A Permissions Policy Generator can simplify browser-feature restrictions, and a Referrer Policy Generator can help compare and construct Referrer-Policy configurations.
Conclusion
Security headers provide browser-enforced protections that can strengthen a web application's security posture. CSP can restrict resource sources, HSTS can enforce HTTPS usage, X-Content-Type-Options can prevent MIME sniffing, Referrer-Policy can reduce unnecessary referrer information, and Permissions-Policy can limit access to browser capabilities.
Other headers such as X-Frame-Options, frame-ancestors, COOP, COEP, and CORP address framing and cross-origin behavior. They are useful in applications that have corresponding security or isolation requirements, but they should not be enabled blindly.
The best security-header configuration is the one that matches the application's actual behavior. Start with a clear baseline, build CSP around real resource requirements, verify HTTPS and HSTS readiness, test cross-origin and third-party integrations, inspect production responses, and review the policies whenever the application changes.