# HTTPS is enforced on all payment and checkout pages

- **Pattern:** `ab-001161` (`ecommerce-payment-security.client-side-handling.https-enforced`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001161
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001161)

## Why it matters

Checkout pages accessed over plain HTTP expose payment form data — billing address, card tokenization requests, and order details — to network observers and man-in-the-middle attackers. PCI-DSS 4.0 Req 4.2 mandates that cardholder data in transit be protected with strong cryptography; CWE-319 (Cleartext Transmission of Sensitive Information) and CWE-523 (Unprotected Transport of Credentials) directly apply. OWASP A02 (Cryptographic Failures) treats unencrypted checkout traffic as a critical failure. Even if the card number itself is tokenized via an iframe, HTTP exposes billing address fields, email, and order totals — enough for targeted phishing or order-manipulation attacks.

## Severity rationale

High because HTTP-accessible checkout pages expose billing details and order data to network observers, violating PCI-DSS 4.0 Req 4.2 and creating a man-in-the-middle attack surface.

## Remediation

Enforce HTTPS at the application layer for defense-in-depth, even when your hosting platform handles it automatically.

```ts
// middleware.ts — redirect HTTP to HTTPS in production
import { NextResponse, type NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  if (
    process.env.NODE_ENV === 'production' &&
    request.headers.get('x-forwarded-proto') === 'http'
  ) {
    return NextResponse.redirect(
      `https://${request.headers.get('host')}${request.nextUrl.pathname}`,
      301
    )
  }
  return NextResponse.next()
}
```

Also set HSTS in `next.config.ts` to prevent browsers from making HTTP requests in the first place:

```ts
{ key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' }
```

## Detection

- **ID:** `https-enforced`
- **Severity:** `high`
- **What to look for:** Count all HTTPS enforcement mechanisms present: middleware redirects, HSTS headers in config, `vercel.json` or `netlify.toml` redirect rules, `Content-Security-Policy` `upgrade-insecure-requests` directives, and platform-level automatic HTTPS. At least 1 enforcement mechanism is required.
- **Pass criteria:** HTTPS is enforced through at least 1 of: HSTS header configuration, explicit HTTP-to-HTTPS redirect middleware, platform-level enforcement (Vercel, Netlify, Cloudflare Pages), or `upgrade-insecure-requests` CSP directive. Checkout pages are not accessible over plain HTTP. Report the count: "X HTTPS enforcement mechanisms found."
- **Fail criteria:** No HTTPS enforcement found at any layer — no platform config, no middleware redirect, no HSTS header. Checkout pages are potentially accessible over HTTP.
- **Skip (N/A) when:** The project is deployed to a platform that enforces HTTPS globally and unconditionally (Vercel, Netlify, Cloudflare Pages) and no custom HTTP-accessible domain configuration overrides this.
- **Detail on fail:** Describe the missing enforcement. Example: `"No HTTPS redirect found in middleware, vercel.json, or next.config.ts. If hosted on a custom server, HTTP access to checkout pages is possible"`
- **Cross-reference:** The Security Headers audit covers HSTS configuration, CSP, and transport security headers in comprehensive detail beyond payment-specific pages.
- **Remediation:** For defense-in-depth, enforce HTTPS at the application level even if your platform handles it:

  ```ts
  // middleware.ts — redirect HTTP to HTTPS
  import { NextResponse, type NextRequest } from 'next/server'

  export function middleware(request: NextRequest) {
    if (
      request.headers.get('x-forwarded-proto') === 'http' &&
      process.env.NODE_ENV === 'production'
    ) {
      return NextResponse.redirect(
        `https://${request.headers.get('host')}${request.nextUrl.pathname}`,
        301
      )
    }
    return NextResponse.next()
  }
  ```

  Also add HSTS to your response headers in `next.config.ts`:

  ```ts
  headers: async () => [{
    source: '/(.*)',
    headers: [{
      key: 'Strict-Transport-Security',
      value: 'max-age=63072000; includeSubDomains; preload',
    }],
  }]
  ```

## External references

- cwe CWE-319
- cwe CWE-523
- owasp A02
- pci-dss Req 4.2

Taxons: cryptography-and-secrets

HTML version: https://auditbuffet.com/patterns/ab-001161
