# OWASP and NIS2 art. 24 compliance for response headers

> Online HTTP response headers analyzer free: CSP, HSTS, X-Frame, Referrer-Policy, Permissions-Policy, COOP/COEP/CORP. Mapped to NIS2 art. 24 and OWASP.

Free in-browser tool (no upload): https://www.mauriziofonte.it/tools/http-security-headers-analyzer

Paste the **response headers** of a web page (cURL, browser DevTools, web archive) and get a security-first audit of hardening controls: **Content-Security-Policy**, **Strict-Transport-Security**, **X-Frame-Options**, **Referrer-Policy**, **Permissions-Policy**, **COOP/COEP/CORP**, anti-fingerprinting. Each finding is severity-coded and mapped to NIS2 art. 24, OWASP Top 10 / ASVS, Mozilla Web Security Cheatsheet.

## How to use the analyzer

1. **Get the response headers** - From terminal: `curl -sI https://yoursite.com`. From browser: DevTools (F12) > Network > click the document request > Headers panel > Response Headers section > copy. Web archive output works as well.
2. **Paste into the tool** - One header per line, standard format `Header-Name: value`. Raw cURL output is accepted (the first line `HTTP/2 200` is filtered automatically). Header names are case-insensitive.
3. **Analyze** - The tool checks 12 security-relevant headers, each with specific rules (CSP must not allow inline scripts or sources open to any host, HSTS must have max-age of at least 180 days, X-Frame-Options must be DENY or SAMEORIGIN, etc). If you paste `curl -IL` output with several responses, only the last one, the final page, is analyzed. Output: severity-coded findings list with normative references and suggested remediation.
4. **Export the report** - Click Copy to get a textual summary you can paste in internal mail, Jira tickets, audit documents. For PDF export use the browser's 'Print' function (the page has a print-optimized stylesheet that hides nav and CTA).

## Why a real audit of HTTP headers matters

**Defense in depth.** HTTP response headers are the thinnest, easiest-to-configure layer of application defenses: emitted by the web server or application middleware, zero performance cost, immediate impact. CSP alone prevents the vast majority of reflected and DOM-based XSS, HSTS closes the TLS downgrade window, X-Frame-Options blocks clickjacking, Permissions-Policy disables unused browser APIs (camera, microphone, geolocation, USB) reducing the attack surface.

**What this tool actually checks.** 12 headers, from essentials (CSP, HSTS, X-Frame-Options, X-Content-Type-Options) to modern ones (COOP/COEP/CORP for cross-origin isolation), with specific rules for each: directives that must be present, sources that must NOT be there (e.g. CSP `unsafe-inline`, `*`, `https:`), correct value format, minimum values (e.g. HSTS `max-age >= 15552000` = 180 days, the Mozilla HTTP Observatory threshold), interactions between headers (e.g. CSP `frame-ancestors` accepted in place of X-Frame-Options, `'unsafe-inline'` ignored by the browser when the same directive has a nonce or a hash). Cache-Control is not judged: headers alone do not tell whether a response is sensitive.

**Standards mapping.** Each finding cites its applicable reference: NIS2 EU Directive 2022/2555 art. 21 c.2 lett. e (security in acquisition / development / maintenance), OWASP Top 10 + ASVS V14, Mozilla Web Security Cheatsheet, RFC 6797 (HSTS), W3C CSP Level 3. For organizations subject to NIS2 this is the starting point of an application-layer audit.

**Privacy by design.** No upload, no remote fetch. The analysis is entirely: your browser parses your headers, evaluates them against local rules, displays the findings. The site you're auditing is never contacted by our server. Useful for auditing internal systems, staging environments not exposed externally, intranet applications.

## Glossary

- **Content-Security-Policy**: HTTP directive instructing the browser which sources (script, style, images, frames, etc) are allowed to load. Primary defense against reflected/stored/DOM-based XSS. Defined by W3C CSP Level 3 (2024).
- **HSTS**: Strict-Transport-Security, RFC 6797. Forces the browser to use HTTPS only for the domain for `max-age` seconds. With `preload` the domain enters the Chrome/Firefox/Safari preload list (manual submission via hstspreload.org).
- **Clickjacking**: Attack where the victim page is loaded in a transparent iframe overlaid on a different page, and user clicks unknowingly hit the victim. Defense: X-Frame-Options or CSP frame-ancestors.
- **Cross-origin isolation**: Combination of COOP=same-origin + COEP=require-corp that enables sensitive browser APIs (SharedArrayBuffer, high-resolution performance.now()) while preventing other origins from reading your data. Required for WASM threads, advanced timing.
- **Permissions-Policy**: W3C header that disables browser features unused by the page (camera, microphone, geolocation, payment, USB, fullscreen, etc). Reduces attack surface and protects sub-frames as well.
- **OWASP ASVS**: Application Security Verification Standard from OWASP (v4.0.3, 2023). Defines 14 categories of application controls across 3 levels (L1-L3). Security header requirements live in V14 'Configuration'.
- **Mozilla Web Security Cheatsheet**: Mozilla's comprehensive reference on web application security, including a section dedicated to security headers with explanation, recommended values, browser support tables.

## Frequently asked questions about the analyzer

### Can I analyze a site by URL only (without pasting headers)?

No, by design. A cross-origin fetch from the browser is blocked by the target page's CORS policy in most cases. To avoid building a server-side proxy (with cost and privacy implications), the tool requires you to paste the headers. Workflow: `curl -sI https://target.com > out.txt`, copy `out.txt`, paste into the tool.

### Is the hardening score a standard metric?

No, it's an indicative triage metric: weighted sum of satisfied controls (CSP +30, HSTS +20, X-Frame-Options or frame-ancestors +10, COOP +10, X-Content-Type-Options +5, Referrer-Policy +5, Permissions-Policy +5, Server header without version +5, no X-Powered-By +5, X-XSS-Protection absent or 0 +5 = 100). A weak CSP earns half the points, and so does HSTS with max-age below 180 days. COEP and CORP produce findings but do not move the score. For industry benchmarks with normalized scoring and continuous monitoring there are dedicated commercial services. This tool is meant for fast triage before a thorough security audit.

### Does the analyzer also check non-security headers (Content-Type, Cache-Control)?

No. Cache-Control matters for security only on sensitive responses (private areas, authenticated APIs), and headers alone do not tell whether a response is one: that is why the tool does not judge it. On those responses, check by hand that `no-store` is there. Content-Type is checked only through `X-Content-Type-Options: nosniff`. For full audits of Content-Type, Vary, Accept-Ranges you need dedicated performance/CDN debugging tools, not security audits.

### Why is X-XSS-Protection flagged as deprecated?

The header has been deprecated by Chrome (2019), Firefox (never seriously supported), Safari. Its XSS heuristic introduced vulnerabilities (XS-Leaks) and was kept only for legacy IE/Edge. OWASP recommends `X-XSS-Protection: 0`, which turns the filter off wherever it still exists: the tool accepts both 0 and a missing header, and flags only the value 1. Modern XSS defense is Content-Security-Policy with strict `script-src`, no `unsafe-inline`, ideally with `nonce` or `hash` on necessary inline scripts.

### I need CSP with unsafe-inline because my legacy site has many onclick. What should I do?

Three gradual strategies. (1) Refactor toward event handlers in external JS (remove onclick=, use addEventListener in the JS). The clean but expensive solution. (2) CSP with `'unsafe-inline'` plus `'nonce-RANDOM'`: the browser accepts inline script with the specific nonce, and giving the nonce to an attacker requires an already-compromised server. Pragmatic compromise. (3) CSP with `'unsafe-hashes'` for inline event handlers (Level 3, 2024+). Browser support is more limited but improving over time.

### Is the Server: nginx/1.24.0 header really dangerous?

Not directly exploitable, but it's a defense-in-depth concept: an attacker enumerating the exact version can search for public exploits for that build. Stable distros (Debian, RHEL) backport patches, so `nginx/1.18.0` Debian buster doesn't have the same vulns as `nginx/1.18.0` upstream, but the automated attacker doesn't know: they see 1.18.0 and try the exploit. Cost to hide: `server_tokens off` in nginx, two lines. Benefit: marginal but free. Under NIS2 art. 21 (cyber hygiene) it's reasonable to do.

### Should I set COOP=same-origin if my site doesn't use SharedArrayBuffer?

Not mandatory, but a good idea. Even without SharedArrayBuffer, COOP prevents specific attacks where another window (phishing popup, page opened by the user) can interact with yours via `window.opener`. `same-origin` isolates your window completely, so other-origin scripts can't read your state. Cost: zero impact on user, marginal on required features.

### Has Permissions-Policy replaced Feature-Policy?

Yes. Feature-Policy was the original name (2018-2020). Permissions-Policy is the standardized name (2020+) with cleaner syntax. Modern browsers support both, but if you serve Permissions-Policy you can remove Feature-Policy. Basic syntax: `Permissions-Policy: camera=(), microphone=(), geolocation=()` = forbid all. `geolocation=(self)` = only current origin.

### How do I get HSTS preload for my domain?

(1) Set HSTS header with `max-age=63072000; includeSubDomains; preload` on all subdomains. (2) Verify it works with `curl -I` and the hstspreload.org checker. (3) Submit the domain on the Chromium portal `hstspreload.org`. Inclusion: weeks-months. Removal: hard, so be sure before submitting. Impact: all HTTP subdomains stop working without a certificate.

### What server-side tools do I use to emit the headers?

Apache: `Header set X-Frame-Options DENY`, `Header set Content-Security-Policy "..."`, in `.htaccess` or virtual host config. Nginx: `add_header X-Frame-Options DENY always;` in the server block. PHP middleware (Symfony, Laravel, Slim): `response->header('X-Frame-Options', 'DENY')` or a dedicated global middleware. For CSP with `nonce`: middleware generates a per-request nonce, emits it in the header, injects it into the `<script nonce="...">` tags.

---
Tool by Maurizio Fonte, senior backend engineer. All tools: https://www.mauriziofonte.it/tools/
