BiTree
  • Search For Lessons
  • Curriculum
  • Pricing
  • For Educators
  • Become a Tutor
  • About
  • Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
BiTree

Live coding lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Search For Lessons
  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Become a Tutor
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 BiTree. All rights reserved.
Curriculum/Web Development/Security for Developers/HTTP Security Headers
45 minIntermediate

HTTP Security Headers

After this lesson, you will be able to: Set a complete, correct set of HTTP security headers (CSP, HSTS, X-Frame-Options/frame-ancestors, X-Content-Type-Options, Referrer-Policy, Permissions-Policy) in Next.js and test them with securityheaders.com and Mozilla Observatory.

HTTP response headers tell the browser how to treat your site, and the right ones block whole classes of attack: cross-site scripting, clickjacking, MIME sniffing, and protocol downgrade. This lesson covers each major security header, how to write a Content-Security-Policy without breaking your own app, how to set them in next.config.js, and how to grade yourself.

Prerequisites:How the Web Works

Where headers live in the request/response cycle

Every HTTP response has a status line, headers, and a body. Headers are metadata: content type, caching, cookies, and security directives. The browser reads security headers before rendering and enforces them. Because they are set once on the response, they are one of the highest-leverage security controls: a few lines of config protect every page.

Content-Security-Policy: the big one

CSP tells the browser which sources of scripts, styles, images, and connections are allowed. A good policy stops most cross-site scripting: even if an attacker injects a <script>, the browser refuses to run it unless it matches the policy. Inline scripts need a nonce (a per-response random value) or a hash. Start in Content-Security-Policy-Report-Only mode, which logs violations without blocking, so you can find what your own app needs before enforcing. The most common mistake is a policy so strict it breaks your own scripts, so test in report-only first.

Setting security headers in next.config.js

Next.js sets response headers via the headers() function. This is a solid baseline; tune the CSP to your app's real sources.

css
// next.config.js
const securityHeaders = [
{
key: "Content-Security-Policy",
value: "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; frame-ancestors 'none'; base-uri 'self';",
},
{ key: "Strict-Transport-Security", value: "max-age=63072000; includeSubDomains; preload" },
{ key: "X-Content-Type-Options", value: "nosniff" },
{ key: "X-Frame-Options", value: "DENY" },
{ key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
{ key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
];
module.exports = {
async headers() {
return [{ source: "/:path*", headers: securityHeaders }];
},
};

Clickjacking, MIME sniffing, HSTS, referrer, permissions

X-Frame-Options: DENY (or CSP frame-ancestors 'none') stops your site being embedded in an attacker's iframe to trick clicks (clickjacking). X-Content-Type-Options: nosniff stops the browser guessing a file's type and executing an uploaded image as a script. Strict-Transport-Security (HSTS) tells browsers to only ever use HTTPS for your domain; includeSubDomains extends it; preload adds you to a list browsers ship with so even the first request is HTTPS. Referrer-Policy controls how much of the URL is sent when users click out (strict-origin-when-cross-origin is a good default). Permissions-Policy disables browser features (camera, mic, geolocation) you do not use, on your pages and in embedded iframes.

Test and grade your headers

Verify after deploying, not just locally.

  1. 1

    1. Deploy with the headers set.

  2. 2

    2. Run your URL through securityheaders.com and read the grade and missing-header notes.

  3. 3

    3. Run it through Mozilla Observatory for a second opinion and CSP analysis.

  4. 4

    4. If CSP breaks something, switch to Content-Security-Policy-Report-Only, collect violation reports, widen the policy to your real sources, then re-enforce.

  5. 5

    5. Re-scan until you have an A.

Quick Check

Your strict CSP is blocking your own analytics script. What is the safest way to fix it without disabling CSP?

Pick one.

Common mistakes only experienced devs catch

Enabling HSTS preload before you are certain every subdomain can do HTTPS forever (preload is hard to undo and can take your site offline on HTTP-only subdomains). Shipping a CSP with 'unsafe-inline' everywhere, which makes it cosmetic. Setting headers only in dev and forgetting they are not applied by your host's CDN. Forgetting frame-ancestors, leaving clickjacking open even with X-Frame-Options missing on some browsers. Testing once and never re-checking after a deploy changes the headers.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Bot Protection and Anti-Scraping
Back to Security for Developers
Secure Authentication Practices→