Skip to main content

Security Headers

What It Is

Security headers are HTTP response headers that tell the browser how to handle security-sensitive behavior.

They help reduce information exposure, control referrer sharing, prevent MIME sniffing, improve XSS protection in older browsers, and force HTTPS usage.

Security Headers = Browser-level security rules sent from the server

Why It Matters

A browser does not only render HTML, CSS, and JavaScript.

It also reads response headers and follows security instructions from the server.

Security headers help protect the app by controlling:

  • what server information is exposed
  • how much referrer information is shared
  • whether MIME types should be trusted
  • whether reflected XSS protection should run in older browsers
  • whether the site should always use HTTPS
Secure frontend = secure code + secure browser instructions

Base Express Server

The PDF starts with a simple Express server.

const express = require("express");

const app = express();

app.get("/list", (req, res) => {
res.send([
{
id: 1,
title: "Namaste Frontend System Design",
},
]);
});

const port = process.env.PORT || 5010;

app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});

When this server runs, some default response headers may be visible in the browser Network tab.

Security headers are added or removed from this server using middleware.


X-Powered-By

X-Powered-By tells what server technology the application is using.

For an Express server, the Network tab may show:

X-Powered-By: Express

This is not a good practice because it exposes implementation details.

If attackers know the server technology, they may try to exploit known issues related to that technology.

X-Powered-By = unnecessary server information exposure

Remove X-Powered-By

Remove the header using Express middleware.

app.use((req, res, next) => {
res.removeHeader("X-Powered-By");

next();
});

After this, the X-Powered-By header will not appear in the Network tab.

Less exposed technology detail = smaller information leak

Referrer-Policy

Referrer-Policy controls how much referrer information is sent with requests.

The browser can send referrer information using the Referer request header.

This may reveal where the user came from.

Referrer-Policy = Controls how much previous-page URL information is shared

The policy can be set using an HTTP header.

It can also be set in HTML.


Referrer-Policy Values

Common values mentioned in the PDF:

Referrer-Policy: no-referrer
Referrer-Policy: no-referrer-when-downgrade
Referrer-Policy: origin
Referrer-Policy: origin-when-cross-origin
Referrer-Policy: same-origin
Referrer-Policy: strict-origin
Referrer-Policy: strict-origin-when-cross-origin
Referrer-Policy: unsafe-url

Each value controls how much referrer data should be included.

For example:

no-referrer = do not send referrer information

Set Referrer-Policy

Example middleware:

app.use((req, res, next) => {
res.setHeader("Referrer-Policy", "no-referrer");
res.removeHeader("X-Powered-By");

next();
});

This configuration removes server technology exposure and prevents referrer information from being sent.

Referrer-Policy: no-referrer = browser sends no referrer information

X-Content-Type-Options

X-Content-Type-Options tells the browser to follow the declared MIME type from the Content-Type header.

It helps avoid MIME type sniffing.

MIME sniffing = Browser guesses file type instead of trusting declared type

Example risk from the PDF:

Client requests a JPG image
Something in the middle modifies the response
HTML or JavaScript is injected
Browser may treat it differently if MIME sniffing is allowed

The server should tell the browser not to guess.


Set X-Content-Type-Options

Use:

X-Content-Type-Options: nosniff

Express middleware:

app.use((req, res, next) => {
res.setHeader("Referrer-Policy", "no-referrer");
res.removeHeader("X-Powered-By");
res.setHeader("X-Content-Type-Options", "nosniff");

next();
});

This tells the browser:

Use the MIME type from Content-Type.
Do not sniff and change it.

X-XSS-Protection

X-XSS-Protection is a response header used by older browsers like Internet Explorer, Chrome, and Safari.

It can stop pages from loading when reflected XSS attacks are detected.

X-XSS-Protection = Older browser reflected XSS protection header

The PDF notes that this protection is largely unnecessary in modern browsers when a strong Content Security Policy is used and inline JavaScript is disabled.


X-XSS-Protection Values

Values mentioned in the PDF:

X-XSS-Protection: 0
X-XSS-Protection: 1
X-XSS-Protection: 1; mode=block
X-XSS-Protection: 1; report=<reporting-uri>

Meaning:

ValueMeaning
0Disable XSS filtering
1Enable XSS filtering
1; mode=blockBlock page loading when attack is detected
1; report=<reporting-uri>Report detected issue to a reporting URI
Modern protection should rely more on strong CSP.

Strict-Transport-Security

Strict-Transport-Security, also called HSTS, tells the browser that the site should only be accessed using HTTPS.

If the user tries to access the site using HTTP later, the browser automatically converts it to HTTPS.

HSTS = Browser should always use HTTPS for this site

This protects communication by forcing secure transport after the browser learns the policy.


HSTS Flow

The PDF explains HSTS in two steps.

1. First insecure request:
User opens HTTP
Server redirects to HTTPS
HTTPS response sets Strict-Transport-Security header

2. Later insecure request:
User opens HTTP again
Browser automatically upgrades to HTTPS

The first request needs a redirect.

After that, the browser remembers the HSTS rule.

First time -> server redirects
Next time -> browser upgrades automatically

Redirect HTTP to HTTPS

The PDF shows a redirect middleware.

const redirectToHttps = (req, res, next) => {
if (req.headers["x-forwarded-proto"] !== "https") {
return res.redirect(["https://", req.get("Host"), req.url].join(""));
}

next();
};

app.use(redirectToHttps);

The PDF also notes:

This may not work in localhost.

Set HSTS Header

Add the HSTS header after redirect handling.

app.use((req, res, next) => {
res.setHeader("Referrer-Policy", "no-referrer");
res.removeHeader("X-Powered-By");
res.setHeader("X-Content-Type-Options", "nosniff");
res.setHeader(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
);

next();
});

This tells the browser to use HTTPS for future requests.

max-age=31536000 = remember HTTPS rule for 1 year
includeSubDomains = apply to subdomains
preload = allow preload-list usage

HSTS Preload

The PDF mentions that if you want the HTTPS upgrade behavior to happen in a single step, the domain needs to be registered in:

hstspreload.org

This is related to preload behavior.

HSTS preload = browser can know HTTPS-only rule before first visit

Complete Middleware Example

A combined security header middleware from the PDF idea looks like this:

const redirectToHttps = (req, res, next) => {
if (req.headers["x-forwarded-proto"] !== "https") {
return res.redirect(["https://", req.get("Host"), req.url].join(""));
}

next();
};

app.use(redirectToHttps);

app.use((req, res, next) => {
res.setHeader("Referrer-Policy", "no-referrer");

res.removeHeader("X-Powered-By");

res.setHeader("X-Content-Type-Options", "nosniff");

res.setHeader(
"Strict-Transport-Security",
"max-age=31536000; includeSubDomains; preload",
);

next();
});

This middleware:

  • redirects HTTP to HTTPS
  • hides Express server details
  • removes referrer sharing
  • disables MIME sniffing
  • enables HTTPS-only behavior

Security Headers Table

HeaderPurpose
X-Powered-ByReveals server technology; should be removed
Referrer-PolicyControls how much referrer information is shared
X-Content-Type-OptionsPrevents MIME type sniffing using nosniff
X-XSS-ProtectionOlder browser XSS filter behavior
Strict-Transport-SecurityForces HTTPS for future requests

Basic Checklist

Check response headers in the browser Network tab
Remove X-Powered-By to avoid exposing server details
Set Referrer-Policy to control referrer information
Use no-referrer when no referrer should be shared
Set X-Content-Type-Options to nosniff
Understand that X-XSS-Protection is mainly for older browsers
Use strong Content-Security-Policy for modern XSS protection
Redirect HTTP requests to HTTPS
Set Strict-Transport-Security for HTTPS-only access
Use includeSubDomains when subdomains should also use HTTPS
Use preload only when the domain is ready for HSTS preload behavior

Interview Style Answer

Security headers are HTTP response headers that instruct the browser how to handle security-related behavior. X-Powered-By exposes the server technology, such as Express, so it should be removed to avoid leaking implementation details. Referrer-Policy controls how much referrer information is sent with requests, and values like no-referrer can prevent sharing the previous page URL. X-Content-Type-Options: nosniff tells the browser to follow the declared Content-Type and avoid MIME type sniffing. X-XSS-Protection is an older browser feature for reflected XSS protection, but modern applications should rely more on strong Content Security Policy. Strict-Transport-Security, or HSTS, tells the browser to always use HTTPS for future requests after the first secure response.


One-Line Summary

Security Headers = Server-sent browser rules that reduce information leaks, unsafe referrers, MIME sniffing, old XSS risks, and insecure HTTP usage.

Final Mental Model

Hide server info -> remove X-Powered-By
Hide referrer info -> Referrer-Policy
Trust declared MIME type -> X-Content-Type-Options: nosniff
Older XSS filter -> X-XSS-Protection
Force HTTPS -> Strict-Transport-Security