HTTPS & TLS
debt(d7/e5/b5/t7)
Closest to 'only careful code review or runtime testing' (d7). No detection_hints.tools are listed. Missing HTTPS, absent HSTS headers, missing Secure cookie flags, and lapsed certificates are not caught by compilers or standard linters — they require manual inspection of server config, HTTP response headers, or runtime network analysis (e.g. browser dev tools, security scanners). Certificate expiry is only noticed when it happens in production.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes installing Certbot and running a command, but a full remediation also requires setting HSTS headers in server config, adding Secure flags to PHP session and auth cookies across the codebase, setting up automated renewal cron jobs, and potentially updating hardcoded HTTP URLs. This spans server config, application cookie configuration, and deployment scripts — more than a single-line patch but not a full architectural rework.
Closest to 'persistent productivity tax' (b5). Once HTTPS is properly configured, ongoing burden is moderate: certificates must be renewed (automate or pay the cost of expiry), HSTS preload considerations constrain future subdomain decisions, and every new cookie set in PHP must have the Secure flag. It affects multiple work streams (ops, backend, deployment) persistently but doesn't redefine the entire system architecture.
Closest to 'serious trap' (t7). The misconception field states it explicitly: developers believe HTTPS only matters for password/payment pages. In reality, any page setting a session cookie over HTTP leaks that cookie to network eavesdroppers. This contradicts intuition that 'public' pages are harmless over HTTP, and the HSTS downgrade attack window is a subtle secondary trap that even security-aware developers often miss. This rises to t7 because the wrong belief is widespread and the consequences are session hijacking.
Also Known As
TL;DR
Explanation
HTTPS is HTTP transmitted over a TLS (Transport Layer Security) connection. TLS provides: confidentiality (data encrypted in transit — only client and server can read it); integrity (tampering is detected via MAC); authentication (the server's identity is verified via its TLS certificate signed by a trusted Certificate Authority). A TLS certificate contains the domain name, issuer, validity period, and the server's public key. Let's Encrypt provides free, automatically-renewing certificates via the ACME protocol (Certbot, acme.sh). Modern TLS configuration: TLS 1.2+ (1.0 and 1.1 deprecated); strong cipher suites; HSTS header (tells browsers to always use HTTPS); HSTS preloading (browsers ship with a list of HTTPS-only domains). In PHP, all cookies should have the Secure flag (HTTPS-only); sessions should set session.cookie_secure = true; API tokens and credentials must only be transmitted over HTTPS.
Common Misconception
Why It Matters
Common Mistakes
- Not setting the Secure flag on cookies — PHP session cookies and authentication cookies must have Secure=true to prevent transmission over HTTP.
- Not configuring HSTS — without it, browsers may make the first request over HTTP before being redirected; HSTS eliminates this window.
- Using self-signed certificates in production — self-signed certs cause browser warnings and are rejected by API clients; use Let's Encrypt.
- Not renewing certificates — Let's Encrypt certificates expire after 90 days; automate renewal with certbot renew in a cron job.
Code Examples
// Cookie without Secure flag — sent over HTTP
setcookie('session', $sessionId, [
'httponly' => true,
// 'secure' => true -- missing! sent over HTTP too
]);
// No HSTS — first request vulnerable
// header('Strict-Transport-Security: ...'); -- missing
// All security flags on session cookie
setcookie('session', $sessionId, [
'expires' => time() + 3600,
'path' => '/',
'secure' => true, // HTTPS only
'httponly' => true, // no JS access
'samesite' => 'Lax', // CSRF protection
]);
// HSTS header — browsers remember HTTPS-only for 1 year
header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
// Redirect HTTP to HTTPS in nginx:
// server { listen 80; return 301 https://$host$request_uri; }