HTTPS
04 / 07

Security Best Practices

HTTP Security Best Practices

Web security at the HTTP layer involves configuring correct headers, enforcing HTTPS, preventing injection attacks, and protecting session cookies. Most vulnerabilities stem from misconfiguration, not exotic exploits.

HTTPS Enforcement

# 1. Redirect all HTTP to HTTPS at the server/CDN level
# nginx:
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$host$request_uri;
}

# 2. Add HSTS header on the HTTPS server
server {
    listen 443 ssl;
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
}

# 3. Submit to HSTS preload list (hstspreload.org)
# Requires: max-age >= 31536000, includeSubDomains, preload

# 4. Next.js - enforce HTTPS + security headers (next.config.js)
const securityHeaders = [
  { key: 'Strict-Transport-Security', value: 'max-age=31536000; includeSubDomains' },
  { key: 'X-Content-Type-Options', value: 'nosniff' },
  { key: 'X-Frame-Options', value: 'SAMEORIGIN' },
  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },
  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },
];
export default {
  async headers() {
    return [{ source: '/(.*)', headers: securityHeaders }];
  },
};

# 5. Test your headers
# https://securityheaders.com
# https://observatory.mozilla.org
curl -sI https://example.com | grep -iE "strict|content-security|x-frame|x-content"

Content Security Policy (CSP)

# CSP restricts what resources a page can load, preventing XSS
# Header: Content-Security-Policy

# Start with report-only mode (logs violations, doesn't block)
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report

# Production CSP
Content-Security-Policy:
  default-src 'self';                          # Default for all types
  script-src 'self' https://cdn.example.com 'nonce-RANDOM';  # Scripts
  style-src 'self' 'unsafe-inline';           # Inline styles (try to avoid)
  img-src 'self' data: https://images.example.com;
  font-src 'self' https://fonts.gstatic.com;
  connect-src 'self' https://api.example.com; # fetch, XHR, WebSocket
  frame-src 'none';                           # No iframes
  object-src 'none';                          # No <object>, <embed>, <applet>
  base-uri 'self';                            # Restrict <base> element
  form-action 'self';                         # Where forms can submit
  upgrade-insecure-requests;                   # Upgrade HTTP sub-resources to HTTPS
  report-uri /csp-report;                      # Where to send violations

# CSP with nonces (preferred over unsafe-inline)
# Server generates random nonce per request:
const nonce = crypto.randomBytes(16).toString('base64');
// Header:
Content-Security-Policy: script-src 'nonce-${nonce}';
// HTML:
<script nonce="${nonce}">/* inline script */</script>

Cookie Security & CORS Config

# Secure cookie configuration
Set-Cookie: session=token; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600

# SameSite values:
# Strict - cookie not sent on cross-site requests at all
#   Best for session cookies when your app is single-domain
# Lax    - sent on safe navigation requests (GET links, not POST/PUT)
#   Default in modern browsers; breaks OAuth flows
# None   - always sent cross-site; REQUIRES Secure flag
#   Required for cross-site embeds, payment iframes, OAuth

# CSRF protection strategies:
# 1. SameSite=Strict/Lax cookies (protects against most CSRF)
# 2. CSRF tokens (synchronizer token pattern)
# 3. Double submit cookies
# 4. Verify Origin/Referer header

# Secure CORS configuration in Express
const corsOptions = {
  origin: function(origin, callback) {
    const allowlist = ['https://app.example.com', 'https://admin.example.com'];
    if (!origin || allowlist.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error(`CORS blocked for origin: ${origin}`));
    }
  },
  credentials: true,
  methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization', 'X-CSRF-Token'],
};
app.options('*', cors(corsOptions));  // Enable pre-flight for all routes
app.use(cors(corsOptions));

Common HTTP-Based Attacks

# 1. Man-in-the-Middle (MITM)
# Attacker intercepts HTTP traffic to read/modify data
# Prevention: HTTPS everywhere, HSTS, certificate transparency

# 2. HTTP Header Injection
# Attacker injects CRLF (\r\n) into header values to add fake headers
# Example: user input "evil\r\nSet-Cookie: admin=true" in Location header
# Prevention: sanitize all values placed into headers; use framework escaping

# 3. Clickjacking
# Attacker embeds your site in an iframe and tricks users into clicking
# Prevention:
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'

# 4. XSS (Cross-Site Scripting) via HTTP responses
# Reflected XSS from API responses injected into DOM
# Prevention: CSP, output encoding, use textContent not innerHTML
Content-Security-Policy: script-src 'self'
X-Content-Type-Options: nosniff   # Prevents MIME sniffing attacks

# 5. CSRF (Cross-Site Request Forgery)
# Malicious site triggers authenticated request to your API
# Prevention: SameSite cookies, CSRF tokens, Origin check
# Check Origin header:
if (req.headers.origin && req.headers.origin !== 'https://app.example.com') {
  return res.status(403).json({ error: 'CSRF check failed' });
}

# 6. HTTP Request Smuggling
# Inconsistent parsing of Transfer-Encoding vs Content-Length between
# frontend proxy and backend server
# Prevention: keep proxy + backend HTTP parsers consistent; upgrade to HTTP/2

# Test your site
# https://observatory.mozilla.org
# https://securityheaders.com
# https://pentest-tools.com/network-vulnerability-scanner
npx snyk test   # Dependency vulnerability scanning

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free