Security Headers for Websites: What to Set and Where
A practical guide to choosing, configuring, testing, and reporting on security headers for marketing websites and web applications.
· 14 min read
A technical auditor can find five missing headers on a single site: X-Content-Type-Options, Content-Security-Policy, Referrer-Policy, X-Frame-Options, and HSTS. Security headers give browsers instructions that can reduce exposure to XSS, clickjacking, insecure connections, and MIME-type confusion—but the useful outcome is a prioritized configuration plan, not a perfect score.
Security headers are response headers sent by a server, framework, CDN, or hosting layer. They are worth auditing because they provide browser-enforced defense in depth. They do not fix vulnerable application code, replace patching or access control, guarantee protection from every attack, or directly improve organic rankings. Google recommends HTTPS for site security, but it does not list a generic security-header checklist as a ranking factor. (developers.google.com)
The practical question from a recent r/bigseo discussion was not merely whether these headers matter, but where an SEO should ask developers to implement them in WordPress or Next.js. The answer depends on the site architecture, third-party scripts, iframe requirements, and whether the site is a brochure site or an authenticated product. (reddit.com)
Why security headers matter for websites
HTTP response headers pass additional information between a server and browser. Security-focused headers use that channel to tell the browser which resources may load, whether a page may appear in an iframe, whether to stay on HTTPS, and whether sensitive browser features should be available. (developer.mozilla.org)
That makes them especially relevant where an attack relies on browser behavior. A malicious script injected into a page may be constrained by a properly designed Content Security Policy (CSP). A login screen cannot be invisibly framed by another origin when frame-ancestors or X-Frame-Options blocks it. A browser that has received HSTS will automatically use HTTPS for later visits to that host. (developer.mozilla.org)
For SEO consultants and agencies, the reporting distinction matters:
- Missing means the expected header is absent on a relevant HTML response.
- Misconfigured means the header exists but is ineffective, contradictory, overly permissive, or breaks a required feature.
- Intentionally omitted means a documented business or technical reason exists, such as a public page that must be embedded in a partner portal.
- Not applicable may apply to some API-only JSON endpoints, where clickjacking controls have no meaningful browser document to protect.
Headers should be reported as security hardening, not as a promise of better rankings or a substitute for a penetration test. OWASP similarly frames secure headers as an application-hardening activity, while noting that missing or incorrect headers can contribute to risks including XSS, clickjacking, and TLS downgrade exposure. (dsomm.owasp.org)
Important security headers: a practical baseline
A normal marketing site rarely needs an exhaustive catalog. The six headers below provide a useful starting point, but values must be tailored to the website rather than copied blindly.
| Header | Primary purpose | Reasonable starting value | Typical location | Common breakage risk |
|---|---|---|---|---|
Content-Security-Policy | Restricts allowed resource sources; helps limit XSS impact | Start in report-only mode; then define explicit sources | App, server, CDN | Analytics, tag managers, inline scripts, embeds |
Strict-Transport-Security | Tells browsers to use HTTPS on future visits | max-age=31536000 after HTTPS validation | Server, CDN, hosting | Certificate or subdomain mistakes; preload commitments |
X-Content-Type-Options | Prevents MIME sniffing | nosniff | Server, CDN, app | Incorrect Content-Type values become visible |
Content-Security-Policy: frame-ancestors | Controls who can embed pages | frame-ancestors 'none' where no embedding is needed | CSP at app/server/CDN | Partner portals, payment flows, embedded forms |
X-Frame-Options | Legacy-compatible anti-framing control | SAMEORIGIN or DENY | Server, CDN, app | Same iframe requirements as above |
Referrer-Policy | Limits referrer detail shared on outbound requests | strict-origin-when-cross-origin | Server, CDN, app | Attribution or debugging expectations |
Permissions-Policy | Limits powerful browser features | Disable unused features, such as camera and microphone | Server, CDN, app | Video, maps, geolocation, embedded tools |
X-Content-Type-Options: nosniff tells browsers to respect the resource MIME type declared in Content-Type rather than sniffing and changing it. It is normally low risk, provided JavaScript, CSS, fonts, and downloads already have correct content types. (developer.mozilla.org)
For clickjacking protection, CSP’s frame-ancestors is the more flexible modern control. OWASP recommends it where possible, and MDN notes that frame-ancestors 'none' has a similar effect to X-Frame-Options: DENY. Keeping X-Frame-Options can still be sensible as a compatibility fallback, but the two must not conflict with an intentional embedding requirement. (cheatsheetseries.owasp.org)
Security headers for a marketing site versus an authenticated app
A five-page marketing site and a SaaS dashboard should not receive exactly the same implementation ticket. Both need HTTPS and sensible browser controls, but the authenticated app has a larger attack surface: login flows, account pages, user-generated content, API calls, payments, and integrations.
Baseline for a typical marketing website
For a site with a contact form, analytics, a consent platform, embedded video, and a CDN, the practical baseline is:
- Enforce HTTPS with redirects, then add HSTS only after every production hostname is ready for HTTPS.
- Set
X-Content-Type-Options: nosniff. - Use
Referrer-Policy: strict-origin-when-cross-originunless a deliberate analytics requirement needs a different policy. - Deny unused browser capabilities through
Permissions-Policy. - Block framing with
frame-ancestors 'none'orX-Frame-Options: DENYunless the page must be embedded. - Deploy CSP in report-only mode before enforcement.
Additional controls for an authenticated application
An application should treat CSP as more than a checkbox. It may need per-request nonces for scripts, a clear allowlist for API and payment origins, form-action 'self' or a limited payment-provider destination, and a policy for user-uploaded content. A generic static CSP copied into a complex app can either break the product or encourage unsafe exceptions such as 'unsafe-inline'.
Next.js documentation specifically describes nonce-based CSP handling for applications and explains that CSP can defend against XSS, clickjacking, and code injection threats. That level of implementation is more appropriate for dynamic applications than for a basic brochure site with no inline code. (nextjs.org)
Content-Security-Policy: roll it out without breaking the site
CSP is usually the highest-value and highest-effort header. It lets administrators control which origins and endpoints the browser may load, helping guard against cross-site scripting when paired with secure coding and output handling. (developer.mozilla.org)
A restrictive policy cannot safely be guessed from a homepage alone. A site may load fonts from one vendor, analytics from another, a video player from a third, and submit forms to a fourth. The policy should be based on observed legitimate behavior across key templates: homepage, blog post, contact page, checkout, account area, and any campaign landing pages.
Start with report-only mode
Use Content-Security-Policy-Report-Only first. Browsers evaluate the proposed policy and report violations without blocking the resources, allowing teams to identify what needs to change before enforcement. (developer.mozilla.org)
An illustrative early policy for a simple site might look like this:
Content-Security-Policy-Report-Only: default-src 'self'; img-src 'self' https: data:; font-src 'self' https:; style-src 'self' 'unsafe-inline' https:; script-src 'self' https:; connect-src 'self' https:; frame-ancestors 'none'; object-src 'none'; base-uri 'self'
This is an example, not a universal production policy. style-src 'unsafe-inline' may be a temporary compatibility compromise for a CMS; script-src 'unsafe-inline' should not be treated as a harmless default. A mature policy should reduce broad allowances, document every third-party origin, and use nonces or hashes where the framework supports them.
Handle iframes and embeds deliberately
frame-ancestors 'none' prevents any other origin from embedding the page. If a customer portal, learning platform, or partner site must embed a specific page, list only the approved parent origins for that route, such as frame-ancestors 'self' https://partner.example. Do not use a permissive setting simply because one page needs embedding.
Likewise, an outbound YouTube, Vimeo, map, chat widget, or payment iframe may require frame-src and perhaps related CSP source directives. Testing must include the exact production user journeys, not just a visual homepage check.
How to add security headers in WordPress
WordPress is commonly the content-management layer, but it is not always the best place to set site-wide headers. The preferred location is the layer that reliably serves every intended response: a CDN or reverse proxy, a web-server configuration, a managed host’s header rules, or WordPress itself where infrastructure access is unavailable.
Best placement order for WordPress
- CDN or hosting control panel: Useful when it applies headers consistently before WordPress and covers cached HTML.
- Nginx or Apache virtual-host configuration: Appropriate for sites with server access and a developer-managed deployment process.
- WordPress configuration or a carefully selected plugin: Useful for managed environments, but it must be tested with page caching, redirects, and plugin updates.
.htaccess: A workable Apache-only route whenmod_headersis enabled, though version-controlled server config is generally easier to govern.
A WordPress theme should not be the primary home for security headers. Themes change, and HTML meta tags are not substitutes for every response header. In particular, X-Frame-Options requires an HTTP response header; a meta tag will not provide the intended control. (developer.mozilla.org)
For Apache, a developer might add this to the relevant virtual host or .htaccess file after confirming mod_headers is available:
<IfModule mod_headers.c>
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>
CSP and HSTS should be added separately and tested more carefully. A WordPress site using Google Tag Manager, a page builder, conversion scripts, or embedded forms can break under a copied CSP. The audit deliverable should therefore name the expected implementation owner—hosting provider, developer, CDN administrator, or WordPress maintainer—and include the affected URLs.
How to configure security headers in Next.js
Next.js supports custom response headers through the headers configuration in next.config.js or next.config.ts. Its current documentation shows that the configuration returns an array of path patterns and header objects, so a team can apply a baseline to all routes with source: '/:path*'. (nextjs.org)
A simple baseline in next.config.js could be:
const securityHeaders = [
{ key: 'X-Content-Type-Options', value: 'nosniff' },
{ key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
{ key: 'X-Frame-Options', value: 'SAMEORIGIN' },
{ key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
{ key: 'Strict-Transport-Security', value: 'max-age=31536000' },
]
module.exports = {
async headers() {
return [{ source: '/:path*', headers: securityHeaders }]
},
}
This snippet deliberately leaves out an enforced CSP because a useful CSP depends on how the app renders scripts and styles. Static applications may be able to use a fixed policy. Apps using inline scripts, third-party tags, or dynamic rendering may require nonces generated per request. Next.js documents a nonce-oriented CSP approach and warns through its implementation guidance that stricter CSP choices affect rendering and deployment decisions. (nextjs.org)
If a platform such as a CDN or hosting provider also adds headers, the team should confirm which layer wins. Duplicate CSP headers can create unexpectedly restrictive combined behavior. A deployment test should inspect the final public response, not just the application repository.
Apache, Nginx, CDN, and HSTS configuration decisions
For Nginx, headers are often set in the server block, typically with always so error responses are covered too:
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
CDNs and hosting panels can be equally valid locations when they support response-header rules. They are often preferable for a distributed site because headers can be added without editing the CMS or application. The downside is governance: a change made only in a vendor dashboard can be hard for an agency or future developer to discover. Record the setting location in the audit.
Treat HSTS as a commitment
HSTS tells browsers to access a host over HTTPS and to upgrade future HTTP attempts. It also means a browser will not allow users to bypass certain certificate errors for that host. (developer.mozilla.org)
A cautious rollout is:
- Confirm every production URL redirects cleanly to HTTPS and every certificate is valid.
- Start with a short
max-age, such as one day, and test real visitor paths. - Increase toward one year only after the site is stable.
- Add
includeSubDomainsonly when every existing and future subdomain can support HTTPS. - Consider HSTS preload only after understanding that removal is slow and operationally difficult.
Preload is not a routine audit recommendation. A forgotten development, mail, customer, or legacy subdomain can become inaccessible in browsers if it cannot serve valid HTTPS.
How to verify website security header configuration
Verification means checking the headers actually returned to visitors. A staging configuration, a code snippet, or a green plugin setting is not evidence that a CDN, redirect, cache, or host has preserved the intended result.
A reviewer can inspect a page in browser DevTools under Network, select the document response, and review response headers. Command-line checks are also useful:
curl -I https://www.example.com/
curl -I -L https://www.example.com/
The second command follows redirects, which matters because a site may configure headers on the final 200 OK response but not on redirects, error pages, language variations, or alternate hostnames. Check at least the canonical homepage, a content page, a form or login page, a 404 page, and a non-www or www variant where applicable.
An auditing workflow can combine header checks with performance, accessibility, broken-link, and technical SEO findings. Audra, for example, can support a local-first site review by helping teams keep page-level findings together for a client-ready report. The implementation recommendation should still be reviewed by the party that controls the server, framework, CDN, or host.
Can I Use is useful for checking browser-support context, particularly for newer policies such as Permissions-Policy; it should inform compatibility decisions rather than become a reason to omit basic hardening without analysis. (caniuse.com)
A client-ready security headers audit checklist
A useful client report avoids a binary “pass/fail” score and documents the decision behind each finding. The following checklist can be applied per hostname and response type:
- Record the tested URL, final status code, redirect chain, and date.
- Capture the exact final response-header values, not only header names.
- Mark each header as present and appropriate, missing, misconfigured, intentionally omitted, or not applicable.
- Identify pages that require iframe embedding, third-party scripts, maps, video, payments, or consent tools.
- Separate low-risk additions such as
nosnifffrom CSP and HSTS changes that require staged rollout. - Check that
Content-Typevalues are correct before enforcingnosniff. - Test CSP in report-only mode across key templates and real conversions before enforcing it.
- Confirm HSTS coverage only after validating all planned subdomains and HTTPS certificates.
- Name the configuration owner and exact change location: Cloudflare rule, Nginx block, Apache virtual host,
next.config.js, WordPress plugin, or managed-host panel. - Retest production after deployment and attach the response-header evidence.
This approach turns “add security headers” into an actionable task. It also prevents an agency from labeling a deliberate integration requirement as a vulnerability without context.
FAQ
What are the important security headers for a website?
For most websites, the starting set is Content-Security-Policy, Strict-Transport-Security, X-Content-Type-Options, Referrer-Policy, Permissions-Policy, and anti-framing protection through CSP frame-ancestors and, where useful, X-Frame-Options. The exact CSP, framing policy, and permissions restrictions vary by site functionality, embeds, and third-party vendors.
Why are HTTP security headers important for website security?
HTTP security headers give compatible browsers enforceable instructions about resource loading, framing, HTTPS use, MIME handling, referrer information, and browser capabilities. They can reduce the impact of attacks such as XSS, clickjacking, and MIME-type sniffing, but they do not repair unsafe server-side code, vulnerable plugins, or weak authentication. (cheatsheetseries.owasp.org)
Where do you add security headers in WordPress?
Headers are best added at the most reliable shared delivery layer: CDN, managed-host header rules, Nginx, Apache, or WordPress only when infrastructure access is unavailable. A WordPress plugin may be appropriate for simple headers, but caching and plugin changes must be tested. CSP and HSTS should be handled with a developer or hosting administrator because incorrect values can break site features.
How do you configure security headers in Next.js?
Next.js supports static response-header rules in next.config.js or next.config.ts using an async headers() function and route patterns such as /:path*. Straightforward headers can be applied globally. CSP requires additional planning: a dynamic Next.js app may need nonce-based handling, precise third-party allowlists, and testing of rendering behavior before enforcement. (nextjs.org)
Which HTTP headers protect against XSS, clickjacking, and MIME-type attacks?
CSP is the main browser control for reducing permitted script and resource sources, so it can help limit XSS impact. CSP frame-ancestors and X-Frame-Options address clickjacking by controlling framing. X-Content-Type-Options: nosniff addresses MIME-type sniffing. Each depends on correct configuration and should complement secure coding, validation, and patch management. (developer.mozilla.org)
Sources
- https://www.reddit.com/r/bigseo/comments/1vyatrj/are_security_headers_important_in_website_if_yes/
- https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html
- https://cheatsheetseries.owasp.org/cheatsheets/Content_Security_Policy_Cheat_Sheet.html
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Content-Security-Policy
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Strict-Transport-Security
- https://nextjs.org/docs/app/api-reference/config/next-config-js/headers
- https://nextjs.org/docs/app/guides/content-security-policy
- https://caniuse.com/contentsecuritypolicy
- https://developers.google.com/search/docs/fundamentals/get-started
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers