
HTTP security headers let a web application tell browsers how to handle resources, browser features, referrers, and framing. They are useful defense in depth, but a copied set of headers can also break sign-in, payments, analytics, embedded content, or other legitimate features.
For a small team, the safe approach is to inventory what the application actually uses, roll out restrictive policies in a mode that does not block users, then enforce them gradually. This guide covers the headers most likely to help a small web application and the trade-offs to check before turning them on.
What security headers can and cannot do
These are HTTP response headers. Configure them at the layer that sends the response, such as your web server, application, reverse proxy, hosting platform, or CDN, not by adding text to a page. If more than one layer already sets a header, inspect the final response first. In particular, multiple Content Security Policy (CSP) policies are all enforced, so adding another policy can make the effective rules more restrictive rather than replace the old ones.
Headers can reduce exposure to certain browser-side attacks and limit what a page or embedded document may do. They do not replace output encoding, input validation, access control, secure session handling, dependency updates, or server-side authorization. A CSP can add protection if a script injection bug slips through, but it is not a substitute for fixing the bug. See MDN's CSP guide and our broader guide to programming with security in mind.
Headers to consider
| Header | What it helps control | Practical starting point |
|---|---|---|
Content-Security-Policy |
Which sources a page may load, and whether it may be embedded | Build a policy for your real resources; test it with the report-only header first |
Permissions-Policy |
Which browser features a page and its frames may use | Disable features the application does not need |
Referrer-Policy |
How much URL information a page sends as a referrer | Use strict-origin-when-cross-origin unless the product has a reason to choose differently |
Strict-Transport-Security |
Whether a browser should use HTTPS for a host in future visits | Enable after HTTPS works consistently; expand the scope cautiously |
X-Content-Type-Options |
Whether the browser may guess a response's content type | Send nosniff and use correct MIME types |
frame-ancestors in CSP |
Which sites may embed a page in a frame | Deny framing unless the product intentionally supports it |
These controls are not a security scorecard. Choose the ones that match your threat model and features, and verify how they behave in the browsers your audience uses.
Start with Content Security Policy in report-only mode
CSP controls where a page can load scripts, styles, images, fonts, connections, and other resources. A carefully designed policy can limit the impact of cross-site scripting, but a policy that is too narrow can block resources your application needs.
Start by listing the resources used on important pages: first-party scripts and styles, API endpoints, fonts, analytics, payment widgets, sign-in providers, and embedded media. Include the parts of the application that behave differently, such as checkout, account settings, and pages with user-generated content.
You can test a proposed policy without enforcing it by returning a Content-Security-Policy-Report-Only header:
Content-Security-Policy-Report-Only: default-src 'self'; object-src 'none'; base-uri 'self'
This is an example to illustrate report-only mode, not a ready-to-deploy policy. It intentionally leaves out application-specific directives. In report-only mode, violations do not block resources, so you can look for legitimate dependencies before enforcing a policy. Browsers can show violations in developer tools; sending reports to a server also requires a configured reporting endpoint and compatible browser support. Do not assume that adding this header alone creates a report log.
Review violations against real user flows. A third-party script may be required for a payment or sign-in flow, but it should not be allowlisted automatically just because it appears in a report. Confirm who owns the domain, what the resource does, and whether a first-party alternative or a narrower source is available. Treat collected reports as untrusted data, and decide how to limit access and retention if they may contain URLs or other sensitive details.
When inline scripts cause violations, prefer removing them or using per-response nonces or hashes where your architecture supports them. Avoid adding 'unsafe-inline' simply to silence reports: it weakens a central benefit of CSP. Once the policy has been exercised across representative pages and browsers, move it to Content-Security-Policy and keep monitoring after releases.
If you use CSP reporting, check which reporting directives and browser versions your endpoint needs to support. MDN notes that the newer report-to mechanism does not yet have full cross-browser support; the older report-uri mechanism is deprecated. Reporting helps with rollout, but testing the actual application remains necessary.
Read MDN's Content-Security-Policy reference and the Content-Security-Policy-Report-Only reference before choosing directives and report handling.
Limit browser features with Permissions Policy
Permissions-Policy lets a site restrict browser features such as camera, microphone, and geolocation. If a web app never needs those features, a policy can prevent its pages and embedded frames from using them:
Permissions-Policy: camera=(), microphone=(), geolocation=()
Do not use this example unchanged if the product uses any of those features. If a feature is needed only on one part of the site, first check whether your hosting or application setup can send an appropriately scoped policy, then test the actual page and any relevant frames. A restrictive header can break a video call, location-based feature, or embedded experience just as easily as it can reduce unnecessary access.
The feature names and browser support are not uniform across every browser version. Check the current MDN Permissions-Policy reference for the directives you plan to use, and do not depend on this header as your only permission or authorization check.
Choose a Referrer Policy for your links and requests
The Referrer-Policy header controls how much of the current page's URL is included when a browser makes a request. A common choice is:
Referrer-Policy: strict-origin-when-cross-origin
This sends the full referrer for same-origin requests, but only the origin for cross-origin requests; it also avoids sending a referrer when navigating from HTTPS to HTTP. This is the default in modern browsers, but setting it explicitly can make your intended behavior easier to review.
If the URL path or query string may contain sensitive information, consider whether a stricter policy such as no-referrer is appropriate. That can also remove referral information your analytics or integrations rely on, so test those use cases before changing it. The MDN Referrer-Policy reference describes the available values and their effects.
Turn on HSTS only after HTTPS is dependable
The Strict-Transport-Security header (HSTS) tells a browser to use HTTPS for future visits to a host. Browsers ignore this header when it is sent over insecure HTTP, so first ensure HTTPS and its redirects work correctly for the site.
For a staged rollout, start with a short max-age on the HTTPS response, verify the site and its subdomains, then increase the duration after you are confident. Browsers remember the policy for that duration, so a mistake can keep affecting visitors after you change the server configuration.
Add includeSubDomains only when every relevant subdomain is ready for HTTPS. Preloading is a separate, long-term commitment: the preload requirements include a max-age of at least one year and includeSubDomains. Do not add it just to satisfy a scanner. Review MDN's HSTS reference and the readiness of every hostname before expanding the policy.
Add MIME-type and framing protections
X-Content-Type-Options: nosniff tells browsers not to guess the content type in certain script and stylesheet requests. Set correct Content-Type values for your files before enabling it; otherwise, browsers may block a script or stylesheet whose declared MIME type does not match its use. See MDN's X-Content-Type-Options reference.
To control which sites can frame your pages, use CSP's frame-ancestors directive. If no site should embed a page, a policy can include:
Content-Security-Policy: frame-ancestors 'none'
If the site needs to embed its own pages, 'self' may be more appropriate; if specific partners need access, allow only those origins. Add the directive to the site's CSP rather than assuming a separate policy will replace an existing one. frame-ancestors must be sent as an HTTP header; placing it in a <meta> element does not enforce it.
X-Frame-Options is an older framing control. Use CSP's frame-ancestors for modern browsers; consider X-Frame-Options only when you need a compatible fallback and can keep the policies consistent. Avoid obsolete values such as ALLOW-FROM. The MDN X-Frame-Options reference explains the limitations.
Roll out changes without surprising users
- Inventory the application. List important routes, scripts, APIs, embedded services, subdomains, and supported browsers. Include flows such as sign-in, checkout, uploads, and account recovery.
- Check current responses. Inspect response headers on the deployed HTTPS site and its important routes. Look for headers already added by the application, host, proxy, or CDN, along with duplicate or conflicting values.
- Test in staging. Apply the proposed settings to a staging environment with realistic integrations. Use CSP report-only mode where appropriate, and exercise both normal and error paths.
- Review findings. Investigate blocked or reported resources instead of allowlisting them blindly. Check browser developer tools, application logs, and any configured reporting endpoint.
- Enforce gradually. Apply the policy to a limited route or audience first when your infrastructure allows it. Watch for broken functionality and have a clear way to revert the configuration.
- Repeat after changes. New analytics, payment providers, embeds, or frontend builds can change which resources the application needs. Recheck the policies as part of release testing.
After deployment, inspect the actual response headers in the browser's Network panel or with an HTTP client. Test more than the homepage: a header missing from an authenticated route, a redirect, or a page served through a different CDN rule can leave a meaningful gap.
A practical baseline
For many small applications, a sensible first pass is to set an explicit referrer policy, send nosniff with correct MIME types, disable browser features the app does not use, and configure HSTS only after HTTPS is dependable. Treat CSP as a separate rollout: inventory resources, monitor a report-only policy, then enforce a policy tested against real workflows. Add framing rules based on whether the product needs to be embedded.
The right configuration is the smallest set of rules that meaningfully reduces exposure without breaking legitimate behavior. Verify it against your application, hosting setup, and supported browsers rather than copying a scanner's suggested values.