Cap device-code poll interval and sweep expired device codes
Two more fixes from the device-flow security review: slow_down interval grew without bound (OidcController): - Each too-fast poll bumped the persisted interval by 5s with no ceiling, so a client polling slightly fast — or an attacker spamming a known device_code — could balloon it (5→10→15→…) past the 10-minute expiry and starve a legitimate client of its token. Clamp the bump to OidcDeviceCode::MAX_INTERVAL (30s); a client polling at the advertised interval is never throttled. Expired device codes accumulated forever (OidcTokenCleanupJob): - Anonymous callers can create device codes via /oauth/device_authorization, and expired/denied/abandoned rows were never reaped. Sweep rows past expiry (with a 1-hour grace to stay clear of in-flight redemption); redeemed codes are already destroyed at token issuance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Q4ATZHoMCWqvSpE2yYoie
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
017dfdff0e
commit
64410a0c50
@@ -611,9 +611,12 @@ class OidcController < ApplicationController
|
||||
|
||||
if device_code.pending?
|
||||
# Enforce the polling interval; too-frequent polls get slow_down, and the
|
||||
# client is expected to add 5s to its interval (RFC 8628 §3.5).
|
||||
# client is expected to add 5s to its interval (RFC 8628 §3.5). The bump is
|
||||
# capped at MAX_INTERVAL so a persistently fast poller can't grow it without
|
||||
# bound and starve a legitimate client before the code expires.
|
||||
if device_code.last_polled_at && (Time.current - device_code.last_polled_at) < device_code.interval
|
||||
device_code.update!(interval: device_code.interval + 5, last_polled_at: Time.current)
|
||||
bumped_interval = [device_code.interval + OidcDeviceCode::INTERVAL_INCREMENT, OidcDeviceCode::MAX_INTERVAL].min
|
||||
device_code.update!(interval: bumped_interval, last_polled_at: Time.current)
|
||||
render json: {error: "slow_down"}, status: :bad_request
|
||||
else
|
||||
device_code.update!(last_polled_at: Time.current)
|
||||
|
||||
Reference in New Issue
Block a user