fix: check the OIDC callback state against the session only #21
Loading…
Reference in a new issue
No description provided.
Delete branch "jtk/oidc-state"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #9 (high): when the session had no
oidc_state, the callback fell back toparams["state"]with a nil nonce, so Assent's state check compared the attacker's value with itself. That's login CSRF: a victim's browser can be signed in as the attacker's account.Changes (
oidc_controller.ex)authorize/2stores Assent'ssession_paramsonce, under:oidc_session_params. (The old:oidc_state/:oidc_noncewrites read string keys from an atom-keyed map, so they were always nil, which is why the fallbacks ever ran.)callback/2reads and deletes:oidc_session_params. No stored state → warning log and "Authentication session expired" flash, never a fallback to the request.state,nonce, PKCEcode_verifier/code_challenge/code_challenge_method) are mapped to atoms, through a fixed table.String.to_atomon session data is gone.Tests
New
test/fuzzy_catalog_web/controllers/oidc_controller_test.exswith a fixedopenid_configuration, so no IdP is called: callback with no session state is refused; callback whose state doesn't match the session fails withAssent.CallbackCSRFErrorand clears the stored params; authorize stores the state that ends up in the redirect URL.mix precommit: 165 tests pass.Worth a manual sign-in against the real IdP after deploy, since the session key changed. Sign-ins started before the deploy will get "session expired" once.
Review by Nye (PR review / audit) — APPROVE @
c8ae0c3Closes #9: callback only reads
:oidc_session_paramsfrom our session, deletes it on use, no params fallback; a fixed atom whitelist replacesString.to_atom. Verified against Assent 0.3.1 source:OAuth2.callbackverify_statedoes a constant-time compare of session state vs param state and config doesn't setstate: false, so a mismatch returnsCallbackCSRFErrorbefore any token call. Also fixes a latent bug: Assent returns atom keys, so the oldsession_params["state"]was always nil. No conflicts with #17, #19 or #20. CI green.Nits (non-blocking): lines ~147-148 still delete legacy
:oidc_state/:oidc_nonce(harmless); no happy-path test (needs a token mock), fine for now.