mirror of
https://github.com/myronblair/parkerslingshotrentals
synced 2026-06-30 17:50:31 -05:00
Fix admin login: replace PHP sessions with HMAC cookie auth
PHP sessions were unreliable on this host — the web process could write session files but LiteSpeed served cached login-page responses on the redirect, bypassing PHP entirely. Replace sessions with a self-contained signed cookie: - On login: generate random 32-byte token + expiry, sign with HMAC-SHA256 - On each request: verify signature and expiry — no filesystem reads needed - Cookie: Secure, HttpOnly, SameSite=Lax, path=/admin/, 24h expiry - admin/.htaccess: CacheEnable off + no-store headers to prevent LiteSpeed from caching admin responses Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+38
-9
@@ -1,23 +1,52 @@
|
||||
<?php
|
||||
require_once dirname(__DIR__) . '/db.php';
|
||||
ini_set('session.save_path', '/home/parkerslingshotrentals.com/sessions');
|
||||
ini_set('session.cookie_httponly', 1);
|
||||
ini_set('session.cookie_samesite', 'Lax');
|
||||
session_start();
|
||||
|
||||
// ── Cookie-based auth (no PHP sessions — avoids server caching/permission issues) ──
|
||||
define('AUTH_COOKIE', 'parker_auth');
|
||||
define('AUTH_SECRET', hash('sha256', ADMIN_PASS . ADMIN_SESSION_KEY)); // not reversible
|
||||
|
||||
function _authToken(): string {
|
||||
$t = bin2hex(random_bytes(32));
|
||||
$e = time() + 86400; // 24h
|
||||
$s = hash_hmac('sha256', "$t|$e", AUTH_SECRET);
|
||||
return "$t.$e.$s";
|
||||
}
|
||||
function _verifyAuth(): bool {
|
||||
$c = $_COOKIE[AUTH_COOKIE] ?? '';
|
||||
$p = explode('.', $c, 3);
|
||||
if (count($p) !== 3) return false;
|
||||
[$t, $e, $s] = $p;
|
||||
if ((int)$e < time()) return false;
|
||||
return hash_equals(hash_hmac('sha256', "$t|$e", AUTH_SECRET), $s);
|
||||
}
|
||||
function _setAuth(): void {
|
||||
$secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
setcookie(AUTH_COOKIE, _authToken(), [
|
||||
'expires' => time() + 86400,
|
||||
'path' => '/admin/',
|
||||
'secure' => $secure,
|
||||
'httponly' => true,
|
||||
'samesite' => 'Lax',
|
||||
]);
|
||||
}
|
||||
function _clearAuth(): void {
|
||||
$secure = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
|
||||
setcookie(AUTH_COOKIE, '', ['expires' => time()-3600, 'path' => '/admin/', 'secure' => $secure, 'httponly' => true, 'samesite' => 'Lax']);
|
||||
}
|
||||
|
||||
$isAjax = !empty($_SERVER['HTTP_X_REQUESTED_WITH']) || (($_SERVER['HTTP_ACCEPT'] ?? '') === 'application/json');
|
||||
|
||||
// ── Auth ──────────────────────────────────────────────────────────────────────
|
||||
if ($_POST['action'] ?? '' === 'login') {
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'login') {
|
||||
if ($_POST['username'] === ADMIN_USER && password_verify($_POST['password'] ?? '', ADMIN_PASS)) {
|
||||
$_SESSION[ADMIN_SESSION_KEY] = true;
|
||||
_setAuth();
|
||||
}
|
||||
header('Location: /admin/'); exit;
|
||||
}
|
||||
if ($_GET['action'] ?? '' === 'logout') {
|
||||
session_destroy(); header('Location: /admin/'); exit;
|
||||
if (($_GET['action'] ?? '') === 'logout') {
|
||||
_clearAuth(); header('Location: /admin/'); exit;
|
||||
}
|
||||
$authed = !empty($_SESSION[ADMIN_SESSION_KEY]);
|
||||
$authed = _verifyAuth();
|
||||
|
||||
// ── AJAX handlers ─────────────────────────────────────────────────────────────
|
||||
if ($isAjax && !$authed) {
|
||||
|
||||
Reference in New Issue
Block a user