Security Headers

⭐ Interview Importance: HIGH
⏱️ Revision Time: 13 min

Security Headers are HTTP response headers that instruct the client’s browser to enable strict security protocols, neutralizing entire classes of attacks like XSS, Clickjacking, and Protocol Downgrades.

Overview

While the helmet package applies many security headers automatically, it is crucial for a backend engineer to understand what those headers actually do, and how to configure them manually if you are using an API Gateway, Nginx, or a framework that doesn’t support Helmet.

Key Concepts

  • HSTS (HTTP Strict Transport Security): Forces the browser to only communicate with your API over HTTPS. If a user accidentally types http://api.com, the browser internally redirects them to https before ever sending the request over the network.
  • X-Content-Type-Options: Prevents the browser from “sniffing” the MIME type. If you send a .txt file that contains Javascript, the browser will refuse to execute it.
  • Referrer-Policy: Controls how much information the browser includes in the Referer header when navigating away from your site.

Code Examples

1. Manual Implementation (Without Helmet)

If you need to set security headers manually in NestJS, you can do so using a global Express middleware.

// security-headers.middleware.ts
import { Injectable, NestMiddleware } from '@nestjs/common';
import { Request, Response, NextFunction } from 'express';

@Injectable()
export class SecurityHeadersMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    // 1. Enforce HTTPS for the next 1 year (31536000 seconds)
    res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
    
    // 2. Prevent Clickjacking (disallow this site from being iframed)
    res.setHeader('X-Frame-Options', 'DENY');
    
    // 3. Prevent MIME-sniffing
    res.setHeader('X-Content-Type-Options', 'nosniff');
    
    // 4. Don't leak the URL path to external sites
    res.setHeader('Referrer-Policy', 'strict-origin-when-cross-origin');
    
    // 5. Basic XSS Protection (mostly obsolete due to CSP, but good for older browsers)
    res.setHeader('X-XSS-Protection', '1; mode=block');

    next();
  }
}

Apply it globally:

// app.module.ts
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { SecurityHeadersMiddleware } from './security-headers.middleware';

@Module({})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer.apply(SecurityHeadersMiddleware).forRoutes('*');
  }
}

2. The Content Security Policy (CSP)

The CSP is the most complex and important header. It is a massive string that dictates exactly what resources the browser is allowed to load.

// A strict CSP for an API that serves a basic Swagger UI
const csp = [
  "default-src 'self'",
  "script-src 'self' 'unsafe-inline'", // Needed for Swagger UI
  "style-src 'self' 'unsafe-inline'",  // Needed for Swagger UI
  "img-src 'self' data:",
  "object-src 'none'", // Block Flash / Java plugins
].join('; ');

res.setHeader('Content-Security-Policy', csp);

Best Practices

  • Use Helmet: Unless you have a very specific reason not to, you should always use the helmet package instead of writing manual middleware. Helmet is constantly updated to reflect the latest browser security standards.
  • HSTS Preloading: If you set the Strict-Transport-Security header, you can submit your domain to hstspreload.org. Your domain will be hardcoded into Chrome, Firefox, and Safari source code, ensuring that no user anywhere in the world will ever be able to access your site via insecure HTTP, even on their very first visit.