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:
| Value | Meaning |
|---|---|
| 0 | Disable XSS filtering |
| 1 | Enable XSS filtering |
| 1; mode=block | Block 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
| Header | Purpose |
|---|---|
| X-Powered-By | Reveals server technology; should be removed |
| Referrer-Policy | Controls how much referrer information is shared |
| X-Content-Type-Options | Prevents MIME type sniffing using nosniff |
| X-XSS-Protection | Older browser XSS filter behavior |
| Strict-Transport-Security | Forces 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