Enforcing HTTPS in PHP — Redirects and HSTS
Enforcing HTTPS in Your PHP Application
Having SSL configured on your server is not enough — you must ensure your PHP application always uses HTTPS and never falls back to insecure HTTP.
Method 1: PHP-Level HTTPS Redirect
Add this at the top of your application's entry point (e.g., index.php or a bootstrap file):
if (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] !== 'on') {
$redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $redirect);
exit();
}
Behind a Load Balancer/Proxy:
If your app is behind a reverse proxy (e.g., AWS ALB, Cloudflare), the proxy terminates SSL and forwards HTTP to your server. Check the X-Forwarded-Proto header instead:
$isHttps = (
(isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') ||
(isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
);if (!$isHttps) {
$redirect = 'https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
header('HTTP/1.1 301 Moved Permanently');
header('Location: ' . $redirect);
exit();
}
Method 2: HSTS (HTTP Strict Transport Security)
HSTS tells browsers to always use HTTPS for your domain, even if the user types http://. This prevents SSL stripping attacks.
// Send HSTS header — browser will enforce HTTPS for 1 year
header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
Parameters explained:
max-age=31536000: Enforce for 1 year (in seconds)
includeSubDomains: Apply to all subdomains too
preload: Allow inclusion in browser preload lists (submit at hstspreload.org)
Method 3: Web Server Redirect (Recommended)
The most efficient approach is redirecting at the web server level:
Nginx:
server {
listen 80;
server_name yourdomain.com;
return 301 https://$server_name$request_uri;
}
Apache (.htaccess):
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Best Practice: Layer Your Defenses
Use all three:
1. Web server redirect (catches all traffic)
2. PHP redirect (defense in depth)
3. HSTS header (prevents future downgrades)