Skip to content

Services, Wiki-Artikel, Blog-Beiträge und Glossar-Einträge durchsuchen

↑↓NavigierenEnterÖffnenESCSchließen
Web-Sicherheit Glossary

HTTP Security Headers

HTTP security headers are response headers that the web server sends with every response to tell the browser how to behave securely—which resources it is allowed to load, whether pages can be embedded in frames, and whether cookies are sent only over HTTPS. They are easy to implement and protect against a range of attacks.

HTTP security headers are one of the easiest ways to improve security in web development: just a few lines of configuration in the web server or code can protect against XSS, clickjacking, MIME type sniffing, and enforce HTTPS. Yet they are missing from an alarming number of live websites—they cost nothing but provide significant protection.

The Most Important Security Headers

Content-Security-Policy (CSP) - Protection against XSS:

  Content-Security-Policy:
    default-src 'self';
    script-src 'self' 'nonce-{RANDOM_PER_REQUEST}';
    style-src 'self' 'unsafe-inline';
    img-src 'self' data: https:;
    font-src 'self' https://fonts.gstatic.com;
    connect-src 'self' https://api.firma.de;
    frame-ancestors 'none';
    base-uri 'self';
    form-action 'self';
    upgrade-insecure-requests;

  Explanation:
    default-src 'self'        → Load only from own origin
    script-src nonce          → Scripts require a per-request nonce
    frame-ancestors 'none'    → Clickjacking protection (like X-Frame-Options)
    upgrade-insecure-requests → HTTP links are upgraded to HTTPS
    base-uri 'self'           → Prevent base tag injection

  Getting Started: Report-Only Mode:
    Content-Security-Policy-Report-Only:
      default-src 'self'; report-uri /csp-report
    → No blocking, only reports → good for testing!

---

Strict-Transport-Security (HSTS) - Enforce HTTPS:

  Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

  max-age=31536000   → 1-year HTTPS requirement stored in the browser
  includeSubDomains  → Also applies to all subdomains
  preload            → Added to browser preload list

  HSTS Preload: hstspreload.org
  → Browser never connects via HTTP - prevents SSL stripping!
  → Caution: Use `includeSubDomains` only when ALL subdomains have HTTPS!

---

X-Frame-Options - Clickjacking protection:

  X-Frame-Options: DENY
  → Page must not be embedded in an iframe anywhere

  X-Frame-Options: SAMEORIGIN
  → Can only be embedded from your own domain

  Note: CSP frame-ancestors is more modern and flexible!
  Set both for maximum browser compatibility.

---

X-Content-Type-Options - Prevent MIME sniffing:

  X-Content-Type-Options: nosniff

  Prevents: Browser guesses MIME type even if server declares it incorrectly
  → HTML file as text/plain → Browser would not execute it as HTML
  → Attack: Upload an image that is actually JavaScript

---

Referrer-Policy - Control referrer information:

  Referrer-Policy: strict-origin-when-cross-origin

  Options:
  no-referrer                   → No Referrer header sent
  no-referrer-when-downgrade    → No Referrer for HTTP→HTTP
  origin                        → Only origin (no paths!)
  strict-origin-when-cross-origin → Origin for cross-site, full for same-site

  Problem without policy:
  User is on https://intern.firma.de/geheimprojekt
  → Clicks on external link
  → Referrer: https://intern.firma.de/geheimprojekt → External site sees URL!

---

Permissions-Policy - Control browser features:

  Permissions-Policy:
    camera=(),
    microphone=(),
    geolocation=(),
    payment=(),
    usb=()

  → Disables access to camera, microphone, GPS, and payment API for embedded content
  → Previously: Feature-Policy header

---

Cross-Origin Headers (Configure CORS correctly):

  Access-Control-Allow-Origin: https://app.firma.de
  → NOT: * (if credentials are sent!)

  Access-Control-Allow-Credentials: true
  → Only if cookies/authentication are truly required!

  Access-Control-Allow-Methods: GET, POST, PUT, DELETE
  Access-Control-Allow-Headers: Content-Type, Authorization

  Dangerous misconfiguration:
  Access-Control-Allow-Origin: *
  Access-Control-Allow-Credentials: true
  → INVALID! Browsers ignore this—but some libraries do not!

Implementation in the Web Server and Code

nginx:
  server {
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
    add_header X-Frame-Options "DENY" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
    add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'none'; upgrade-insecure-requests;" always;
    # "always" → send even with 4xx/5xx responses!
  }

---

Apache:
  <IfModule mod_headers.c>
    Header always set Strict-Transport-Security &quot;max-age=31536000; includeSubDomains&quot;
    Header always set X-Frame-Options &quot;DENY&quot;
    Header always set X-Content-Type-Options &quot;nosniff&quot;
    Header always set Referrer-Policy &quot;strict-origin-when-cross-origin&quot;---
  </IfModule>



Express.js (Node.js) with Helmet:
  import helmet from &#x27;helmet&#x27;;

  app.use(helmet({
    contentSecurityPolicy: {
      directives: {
        defaultSrc: [&quot;&#x27;self&#x27;&quot;],
        scriptSrc: [&quot;&#x27;self&#x27;&quot;],
        styleSrc: [&quot;&#x27;self&#x27;&quot;, &quot;&#x27;unsafe-inline&#x27;&quot;],
        imgSrc: [&quot;&#x27;self&#x27;&quot;, &quot;data:&quot;, &quot;https:&quot;],
        frameAncestors: [&quot;&#x27;none&#x27;&quot;],
        upgradeInsecureRequests: [],
      }
    },
    hsts: {
      maxAge: 31536000,
      includeSubDomains: true,
      preload: true,
    },
    frameguard: { action: &#x27;deny&#x27; },
    noSniff: true,
    referrerPolicy: { policy: &#x27;strict-origin-when-cross-origin&#x27; },
  }));

---

Astro.js (SSG/SSR):
  // astro.config.mjs:
  export default defineConfig({
    server: {
      headers: {
        &#x27;X-Frame-Options&#x27;: &#x27;DENY&#x27;,
        &#x27;X-Content-Type-Options&#x27;: &#x27;nosniff&#x27;,
        &#x27;Referrer-Policy&#x27;: &#x27;strict-origin-when-cross-origin&#x27;,
      }
    }
  });

Security Header Testing

Online Tools:
  → securityheaders.com: Report for each URL
  → Mozilla Observatory (observatory.mozilla.org): A-F Score
  → HSTS Preload Check: hstspreload.org

Local Tests:
  # curl check:
  curl -I https://yoursite.de | grep -i &quot;content-security\|x-frame\|strict-transport\|x-content\|referrer&quot;

  # nikto (HTTP Header Check):
  nikto -h https://yoursite.de -Plugins headers

Scoring:
  Mozilla Observatory Score:
  A+ (100/100): All important headers set, strict CSP
  B  (55-74):   Most headers, CSP present but lenient
  D  (&lt;40):     Missing HSTS or CSP

  Goal: A or A+ on Mozilla Observatory

Typical findings in the pentest (missing headers):
  □ No HSTS → SSL stripping possible
  □ No X-Frame-Options → Clickjacking possible
  □ No X-Content-Type-Options → MIME sniffing
  □ No CSP → XSS without mitigation
  □ Wide CORS (*) → Cross-origin access
  □ Server header shows version: &quot;Server: Apache/2.4.51&quot;
    → Remove version disclosure: ServerTokens Prod (Apache)