HTTP Security Headers: Your Practical Guide to Safer Web Apps (Part 2)
- Avinash Ghadshi
- Aug 23
- 5 min read
In Part 1, we explored the foundational HTTP security headers you can implement immediately to strengthen your web apps. Now, it’s time to level up. In this part, we’ll dive into advanced and modern security headers that control features: Permissions-Policy, Cross-Origin-Resource Policy, Cross-Origin-Opener Policy, Cross-Origin-Embedder Policy. and Cache-Control. These headers help you enforce tighter controls in your apps, protect sensitive resources, and prepare your architecture for modern browser security models like COOP+COEP isolation.
Missed Part 1? Read it here: HTTP Security Headers: Foundations for Safer Web Apps
Let’s explore these headers one by one, with practical examples, implementation tips, and testing guidance so you can confidently add them to your stack.
Permissions-Policy(formerly Feature-Policy)
Controls access to browser features (camera, geolocation, microphone) for your site and embedded content.
Example
Permissions-Policy: geolocation=(), microphone=(), camera=()
geolocation is allowed only for the same origin (self).
camera is blocked for all origins.
What happens to the rest of the features?
Only the explicitly mentioned features (geolocation, camera) are controlled by your policy.
All other features retain their browser default behaviour (typically: enabled and controlled by user prompts/permissions).
They are NOT auto-blocked unless explicitly specified.
Permissions-Policy Directives CheatSheet

How it works?

Client(browser) Sends Request to your server to fetch a page.
Server Responds with Permission-Policy Header
Permission-Policy: geolocation=(self), camera=()
is included in the HTTP response headers.
Browser Parses the Header
Identifies which features are explicitly listed (geolocation, camera).
Checks the allowed origins for each:
geolocation=(self) → Allowed only if the origin is the same.
camera=() → Disallowed everywhere.
Applies Allow/Deny for Listed Features
geolocation will work only on your domain.
camera is blocked globally.
Unlisted Features Use Browser Defaults
Features not listed (e.g., microphone, notifications) remain at browser default behaviour:
Typically enabled but require user permission prompts.
Not auto-blocked unless explicitly set.
Result: Controlled Feature Availability
Only explicitly listed features are managed by the header.
Others behave as usual unless you add them to the header in the future.
Cross-Origin-Resource-Policy (CORP)
Cross-Origin-Resource-Policy is an HTTP response header that tells the browser whether a resource can be shared with documents from other origins. It helps prevent cross-origin data leaks by restricting who can load the resource.
Example
Cross-Origin-Resource-Policy: same-origin
same-origin: Only the same origin can load the resource.
same-site: Any origin on the same site (eTLD+1) can load it.
cross-origin: Any origin can load the resource (default, permissive).
How it works?

Browser sends a request for an image, script, font, or other resource.
Server Responds with CORP Header
Cross-Origin-Resource-Policy: same-origin
Browser Checks the Origin of the Requesting Document:
If the document's origin matches:
Resource loads successfully.
If not:
Resource load is blocked, protecting data leakage across origins.
Effect:
Helps prevent cross-origin data leaks when combined with COEP (Cross-Origin-Embedder-Policy) for high-security isolation.
Useful for images, scripts, fonts on your domain that should not be accessible by other sites.
Cross-Origin-Opener-Policy (COOP)
COOP (Cross-Origin-Opener-Policy) is a security setting you add to your website.
It blocks other websites (different origins) from messing with your page if they open it in a new window or tab.
Normally, if a site opens your page, it can still communicate with it using window.opener.
Bad sites can use this to steal data or perform attacks.
By using COOP, you cut this connection with different sites, so they cannot interact with your page.
It keeps your page safe and isolated and prepares it for using advanced browser features securely (when combined with COEP).
Example
Cross-Origin-Opener-Policy: same-origin
If your page opens a popup or is opened as a popup,
The opener relationship is severed if the popup is from a different origin.
Available Options
same-origin: Isolate the browsing context if the top-level document has a different origin.
same-origin-allow-popups: Same as same-origin but allows popups to be opened without being isolated from the opener.
unsafe-none: No isolation (default).
How it works?

Browser requests page.
Server responds with Cross-Origin-Opener-Policy.
Browser:
Checks if COOP = same-origin and if opener’s origin is different.
If different, breaks window.opener link.
If same, allows the opener link.
Page is loaded with isolated or linked browsing context accordingly.
Cross-Origin-Embedder-Policy (COEP)
COEP is an HTTP response header that requires all resources loaded by your page to grant explicit permission to be loaded cross-origin.
It helps enforce cross-origin isolation, which is needed for powerful web features like SharedArrayBuffer, high-resolution timers, and other advanced APIs.
COEP works together with Cross-Origin-Opener-Policy (COOP) to enable full cross-origin isolation.
Imagine your website is a secured room.
You only want to bring in packages (images, scripts, etc.) from outside if they are clearly labeled and safe.
COEP tells the browser:
“Only allow resources that say they’re okay to be used by other sites, or that come from my own site.”
Example:
Cross-Origin-Embedder-Policy: require-corp
Your page will only load cross-origin resources if they send Cross-Origin-Resource-Policy: cross-origin or are from the same origin.
Needed to enable cross-origin isolation for using high-resolution timers and SharedArrayBuffer
Available Options
unsafe-none: Default. No cross-origin embedding restrictions.
require-corp: Requires all loaded cross-origin resources to send proper Cross-Origin-Resource-Policy (CORP) headers.
How it works?

Your page includes Cross-Origin-Embedder-Policy: require-corp.
When your page requests a cross-origin resource (like an image, script, or worker), the browser checks if that resource includes Cross-Origin-Resource-Policy: cross-origin.
If the resource does not have a proper CORP header, the browser blocks it to prevent cross-origin leaks.
Combined with COOP, this fully isolates your site from other origins in the browser.
Cache-Control
When configured securely can help prevent sensitive data from being cached publicly.
Cache-Control is an HTTP header that tells browsers and intermediate caches (like CDNs or proxies) how to store and reuse responses.
It helps improve performance and reduce server load by controlling whether content can be cached, how long it should be stored, and under what conditions it must be revalidated.
Example:
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
no-store: Do not save this response anywhere (not in browser cache, not in proxy, not on disk).
no-cache: Can store temporarily, but must check with the server before using it (revalidate).
must-revalidate: Even if cache exists, it must always re-check with the server before serving.
max-age: Cached content is considered immediately stale (expires instantly).
Cache-Control CheatSheet

How it works?

Browser makes a request.
Server responds with Cache-Control header.
Browser (and possibly proxy/CDN) reads directives:
If no-store: don’t save it at all.
If max-age: save it for that duration.
If no-cache or must-revalidate: save but always re-check with server.
If public or private: defines who can cache it.
On the next request, browser decides:
Serve from cache (if still valid).
Or revalidate with server (if expired/required).
Or fetch fresh (if not allowed to use cache).
HTTP security headers may look small, but they act as powerful shields for your application. By configuring them correctly—whether it’s enforcing HTTPS with HSTS, preventing clickjacking with X-Frame-Options, controlling data leaks with CSP, or managing resource isolation with COOP/COEP—you add critical layers of defense that work silently in the background. Think of them as your app’s first line of defense before code or firewalls even come into play. At CodingCipher, we believe secure coding isn’t optional—it’s a habit. Start with these headers, test them regularly, and make security a default part of your development lifecycle.
In the next blog, I’ll share a handy script to automatically check the HTTP headers of any given URL, so you can audit your endpoints with ease.
Stay tuned! Keep Learning! Keep Growing!
Comments