fix(session): write expires_at in UTC, not local time (audit 6c-2)
CreateSession wrote FormatDateTime(IncHour(Now,24)) = local, but RequireCSRF
and CleanupExpired compare against SQLite datetime('now') = UTC. On negative
UTC offsets the CSRF window fell short of the 24h auth window: between the two,
GETs authed fine but every write got 403 "Invalid CSRF token". Now
IncHour(NowUTC,24) on write + LExpires < NowUTC in Authenticate, so all three
readers are UTC-consistent. Last FormatDateTime(...,Now) in the backend —
closes §2.2 for real. NowUTC + DateUtils already in uses.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -86,7 +86,8 @@ begin
|
||||
LQ.Free;
|
||||
end;
|
||||
|
||||
if (LExpires <> 0) and (LExpires < Now) then
|
||||
// expires_at is now UTC (see CreateSession) — compare against UTC too.
|
||||
if (LExpires <> 0) and (LExpires < NowUTC) then
|
||||
begin
|
||||
DeleteSessionByTokenHash(LTokenHash);
|
||||
TJSONHelper.SendError(AResponse, 401, 'Session expired');
|
||||
@@ -152,7 +153,11 @@ begin
|
||||
ACSRFToken := RandomHex(32);
|
||||
LTokenHash := SHA256Hex(AToken);
|
||||
// YYYY-MM-DD HH:NN:SS, +24h, server local time (api.php uses date() = local)
|
||||
LExpires := FormatDateTime('yyyy-mm-dd hh:nn:ss', IncHour(Now, 24));
|
||||
// UTC like everywhere else — RequireCSRF + CleanupExpired compare against
|
||||
// SQLite datetime('now') which IS UTC. Writing local here made the CSRF
|
||||
// window fall short on negative-offset zones (§6c-2): "Invalid CSRF token"
|
||||
// on writes while GETs still authed.
|
||||
LExpires := FormatDateTime('yyyy-mm-dd hh:nn:ss', IncHour(NowUTC, 24));
|
||||
|
||||
DB.Lock;
|
||||
try
|
||||
|
||||
Reference in New Issue
Block a user