Security Hardening: Phase 1-3 complete
- C1: Hash refresh tokens before DB storage (sha256) - C2: Remove JWT_SECRET fallback, fail hard if missing - H1: Enforce HTTP methods per route (405 on mismatch) - H2: CORS with origin whitelist from CORS_ORIGIN env var - H3: Redact sensitive fields (tokens, passwords) from logs - M1: Build HmacMiddleware with replay attack prevention - M2: Fix rate limiter race condition with flock LOCK_EX - M3: Guard dd() — suppressed in production - M4: Remove .env from git tracking, strengthen .gitignore - I1: Add HSTS header (max-age=31536000)
This commit is contained in:
@@ -14,15 +14,20 @@ if (!$refreshToken) {
|
||||
}
|
||||
|
||||
$db = Database::getInstance();
|
||||
$refreshTokenHash = hash('sha256', $refreshToken);
|
||||
$stmt = $db->prepare("SELECT * FROM users WHERE refresh_token_hash = ? LIMIT 1");
|
||||
$stmt->execute([$refreshToken]);
|
||||
$stmt->execute([$refreshTokenHash]);
|
||||
$user = $stmt->fetch();
|
||||
|
||||
if (!$user) {
|
||||
json_error('Invalid refresh token', 401);
|
||||
}
|
||||
|
||||
$secret = env('JWT_SECRET', 'super-secret-key');
|
||||
$secret = env('JWT_SECRET');
|
||||
if (!$secret || strlen($secret) < 32) {
|
||||
error_log('FATAL: JWT_SECRET is missing or too short in .env');
|
||||
json_error('Server configuration error', 500);
|
||||
}
|
||||
$payload = [
|
||||
'user_id' => $user['id'],
|
||||
'role' => $user['role'],
|
||||
@@ -31,9 +36,10 @@ $payload = [
|
||||
|
||||
$newToken = JWT::encode($payload, $secret);
|
||||
$newRefreshToken = bin2hex(random_bytes(32));
|
||||
$newRefreshTokenHash = hash('sha256', $newRefreshToken);
|
||||
|
||||
$stmt = $db->prepare("UPDATE users SET refresh_token_hash = ? WHERE id = ?");
|
||||
$stmt->execute([$newRefreshToken, $user['id']]);
|
||||
$stmt->execute([$newRefreshTokenHash, $user['id']]);
|
||||
|
||||
json_success([
|
||||
'access_token' => $newToken,
|
||||
|
||||
Reference in New Issue
Block a user