View as Json

Security Headers

Security Headers provides a unified configuration for protecting your Express applications from common web vulnerabilities like Cross-Site Scripting (XSS), Clickjacking, and Cross-Origin Resource Sharing (CORS) issues.


Installation Guide

Install the component using the servercn CLI:

npx servercn-cli add security-header

Threat Model Coverage

Below is a precise breakdown of each header, the associated attack vector, and the mitigation strategy.

Attack:

Browsers attempt MIME sniffing and may execute JavaScript disguised as another file type (e.g., malicious JS embedded in an image upload).

Mitigation:

Forces browsers to strictly honor the declared Content-Type header.


Attack (Clickjacking):

An attacker embeds your application inside a malicious iframe and overlays invisible UI elements to trick users into clicking privileged actions.

Mitigation:

Prevents your application from being framed.


History & Risk:

Legacy browsers implemented a reflective XSS filter that was unreliable and, in some cases, exploitable.

Modern Best Practice:

Disable it (0) and rely on a properly configured Content-Security-Policy (CSP).


Attack (Protocol Downgrade / MITM):

An attacker forces HTTPS traffic to downgrade to HTTP.

Mitigation:

Instructs the browser to only use HTTPS for your domain for a defined duration.


Attack (XSS Injection):

An attacker injects malicious <script> tags into your pages.

Mitigation:

Whitelists allowed script, style, image, and connection sources.


Data Leakage Risk:

The Referer header may expose full URLs including tokens, internal paths, or identifiers when navigating away.

Mitigation:

Controls how much URL information is shared with external origins.


Attack Surface Expansion:

Malicious embedded contexts (iframes) attempt to access camera, microphone, geolocation, etc.

Mitigation:

Explicitly disables browser capabilities your application does not require.


Information Disclosure:

X-Powered-By: Express reveals your framework stack.

Mitigation:

Disable to reduce reconnaissance surface area.


Basic Implementation

The component provides a configureSecurityHeaders function that you should call during your Express app initialization.

Minimal

src/middlewares/security-header.ts
import cors from "cors";
import { Express } from "express";
import helmet from "helmet";
 
export const configureSecurityHeaders = (app: Express) => {
  app.use(helmet());
 
  app.use(
    cors({
      origin: process.env.CORS_ORIGIN || "*",
      credentials: true,
      methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
      allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"]
    })
  );
 
  app.use((req, res, next) => {
    res.setHeader("X-Content-Type-Options", "nosniff");
    res.setHeader("X-Frame-Options", "DENY");
    res.setHeader("X-XSS-Protection", "1; mode=block");
    next();
  });
};

Advanced

src/middlewares/security-header.ts
import cors from "cors";
import { Express } from "express";
import helmet from "helmet";
 
export const configureSecurityHeaders = (app: Express) => {
  // Remove framework fingerprint
  app.disable("x-powered-by");
 
  // Helmet with explicit security policy configuration
  app.use(
    helmet({
      xssFilter: false, // disable legacy X-XSS-Protection
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          scriptSrc: ["'self'"],
          styleSrc: ["'self'"],
          imgSrc: ["'self'", "data:"],
          connectSrc: ["'self'"],
          objectSrc: ["'none'"],
          frameAncestors: ["'none'"],
          upgradeInsecureRequests: []
        }
      },
      hsts: {
        maxAge: 63072000, // 2 years
        includeSubDomains: true,
        preload: true
      },
      referrerPolicy: {
        policy: "strict-origin-when-cross-origin"
      },
      permissionsPolicy: {
        features: {
          camera: [],
          microphone: [],
          geolocation: [],
          payment: []
        }
      }
    })
  );
 
  // CORS configuration
  app.use(
    cors({
      origin: process.env.CORS_ORIGIN || "*",
      credentials: true,
      methods: ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"],
      allowedHeaders: ["Content-Type", "Authorization", "X-Requested-With"]
    })
  );
 
  // Explicit header hardening overrides
  app.use((req, res, next) => {
    res.setHeader("X-Content-Type-Options", "nosniff");
    res.setHeader("X-Frame-Options", "DENY");
    res.setHeader("X-XSS-Protection", "0"); // modern best practice
    next();
  });
};

Import and use the configuration in your main app.ts file.

src/app.ts
import express from "express";
import { configureSecurityHeaders } from "./middlewares/security-header";
 
const app = express();
 
// Apply security headers before other middlewares and routes
configureSecurityHeaders(app);
 
app.use(express.json());
// ... rest of your app

Production Recommendations

Never use * in production for authenticated APIs.

cors({
  origin: "https://your-frontend-domain.com"
  // ...
});

If using CDNs or third-party services:

app.use(
  helmet({
    contentSecurityPolicy: {
      directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'", "trusted-scripts.com"],
        imgSrc: ["'self'", "res.cloudinary.com"]
      }
    }
  })
);

Once deployed over HTTPS permanently, consider submitting to the HSTS preload list.


Verification

You can verify your security headers using online tools like SecurityHeaders.com.

File & Folder Structure

Loading files...

Installation

npx servercn-cli add security-header