OAuth-beveiligingstestchecklist: high-impact authenticatiebugs vinden
OAuth 2.0-kwetsbaarheden staan consequent bovenaan de lijst voor bug bounty-uitbetalingen met kritieke ernst. Een enkele account-takeover via OAuth-misconfiguratie kan escaleren naar volledige organisatorische compromittering — en deze bugs komen voor in applicaties die door miljarden mensen worden gebruikt.
- $10K-$100K — OAuth ATO-uitbetalingen
- Kritiek — Impactclassificatie
- 4,2 miljard+ — Wereldwijd getroffen gebruikers
- OWASP A07 — ID- & authenticatiefouten
OAuth 2.0-fundamenten voor beveiligingstesten
Begrijpen welke stroom een doelwit gebruikt bepaalt welke aanvallen te testen. De Authorization Code-stroom (met PKCE) is het veiligst en meest gebruikelijk. De inmiddels verouderde Implicit-stroom heeft talrijke kwetsbaarheden. Client Credentials (machine-naar-machine) heeft zijn eigen aanvalsoppervlak. Nooit gebruiken in productie: Resource Owner Password Credentials.
Belangrijkste OAuth-componenten
- Authorization Server (AS) — Geeft tokens uit (bijv. Google, Okta, Auth0)
- Resource Server (RS) — API die tokens accepteert
- Client — Uw applicatie die toegang aanvraagt
- Resource Owner — De gebruiker die toegang verleent
- Autorisatiecode — Kortlevende, eenmalig bruikbare code uitgewisseld voor tokens
- Access Token — Bearer-token voor API-toegang
- Refresh Token — Langlevend token om nieuwe access tokens te verkrijgen
- PKCE — Proof Key for Code Exchange (voorkomt code-onderschepping)
Sectie 1: onderschepping van autorisatiecodes
Test 1.1 — Open redirect in redirect_uri
Als de autorisatieserver redirect_uri met onvoldoende precisie valideert, kan een aanvaller de autorisatiecode omleiden naar hun beheerde server.
# Legitimate request
https://auth.example.com/oauth/authorize?
client_id=app123&
redirect_uri=https://app.com/callback&
response_type=code&state=xyz
# Attack attempts
# 1. Path traversal
redirect_uri=https://app.com/callback/../../../evil.com/steal
# 2. Additional path
redirect_uri=https://app.com.evil.com/callback
# 3. Fragment bypass
redirect_uri=https://app.com/callback%23@evil.com
# 4. Query string bypass
redirect_uri=https://app.com/callback?next=https://evil.com
Test 1.2 — Validatie van de state-parameter
De state-parameter voorkomt CSRF-aanvallen tijdens OAuth-stromen. Indien afwezig of voorspelbaar, kan een aanvaller slachtoffers dwingen hun accounts te koppelen aan door de aanvaller beheerde identiteiten — wat account-takeover mogelijk maakt.
# Check if state is:
# 1. Present in authorization request
# 2. Validated on callback
# 3. Cryptographically random (not sequential/predictable)
# 4. Single-use (replayed states should be rejected)
# Test: replay the same state parameter
curl -s "https://app.com/oauth/callback?code=VALID_CODE&state=PREVIOUSLY_USED_STATE"
# Should return: error (state already used)
Test 1.3 — Hergebruik van code
# Authorization codes must be single-use
# Test by replaying the code after first exchange:
# First use (legitimate)
POST /oauth/token
code=AUTH_CODE_123&grant_type=authorization_code&...
# Second use (should fail)
POST /oauth/token
code=AUTH_CODE_123&grant_type=authorization_code&...
# Expected: {"error": "invalid_grant"}
Sectie 2: PKCE-bypasstesten
Test 2.1 — PKCE-handhaving
PKCE voorkomt aanvallen die autorisatiecodes onderscheppen. Als een server die PKCE ondersteunt dit niet handhaaft, zijn publieke clients kwetsbaar.
# Start flow WITH PKCE (legitimate)
code_verifier = generate_random_string(64)
code_challenge = base64url(sha256(code_verifier))
GET /authorize?
code_challenge=abc123&
code_challenge_method=S256&...
# Attack: exchange code WITHOUT providing code_verifier
POST /token
grant_type=authorization_code&
code=INTERCEPTED_CODE&
redirect_uri=https://legitimate-app.com/callback
# Missing: code_verifier
# If this succeeds -> PKCE not enforced -> Critical vulnerability
Test 2.2 — Downgrade van code_challenge_method
# Attempt to downgrade from S256 to plain (less secure)
GET /authorize?
code_challenge=ACTUAL_CODE_VERIFIER&
code_challenge_method=plain&...
# If accepted: server may be using plain instead of S256
# Then exchange with code_verifier = original plain text
POST /token
code_verifier=ORIGINAL_PLAIN_TEXT&...
Sectie 3: tokenkwetsbaarheden
Test 3.1 — Lekkage van access token via Referrer
In de Implicit-stroom (verouderd maar nog steeds aangetroffen) worden access tokens in URL-fragmenten (#access_token=...) niet meegestuurd in Referer-headers — maar tokens in queryparameters (?access_token=...) wel. Controleer altijd hoe tokens in URL's verschijnen.
Test 3.2 — Escalatie van tokenscope
# Request minimal scope
GET /authorize?scope=read:email&...
# After getting access token, test unauthorized API calls
GET /api/user/delete
Authorization: Bearer ACCESS_TOKEN_WITH_READ_SCOPE
# Should return 403, not 200
Test 3.3 — JWT access token-kwetsbaarheden
# If access tokens are JWTs, test:
# 1. Algorithm confusion (RS256 -> HS256)
header = {"alg": "HS256", "typ": "JWT"}
# Sign with the public key as HMAC secret
# 2. None algorithm
header = {"alg": "none", "typ": "JWT"}
# Some libraries accept unsigned tokens
# 3. Kid injection (if 'kid' is used)
header = {"alg": "HS256", "kid": "' OR 1=1--"}
# SQL injection in kid parameter
# Tools:
# jwt_tool: python3 jwt_tool.py TOKEN -T (tamper)
# jwt-cracker: for weak secrets
Test 3.4 — Bypass van refresh token-rotatie
# Test if old refresh tokens are invalidated after rotation
POST /token
grant_type=refresh_token&refresh_token=OLD_REFRESH_TOKEN
# If this returns a new token -> old token not invalidated
# Attacker who stole old refresh token can still get new access tokens
Sectie 4: account-takeover-scenario's
Test 4.1 — OAuth-accountkoppeling zonder e-mailverificatie
Als een slachtoffer zich aanmeldt met e-mail/wachtwoord (e-mail: victim@gmail.com) en een aanvaller een Google OAuth-account met hetzelfde e-mailadres kan koppelen om het account van het slachtoffer over te nemen — zonder dat Google eigendom verifieert — is dat een kritieke account-takeover. Dit komt vooral vaak voor op platforms die het koppelen van meerdere authenticatieproviders toestaan.
Test 4.2 — Pre-account-takeover
# Attack scenario:
# 1. Attacker creates account with victim@example.com (before victim registers)
# 2. Attacker links their OAuth provider to this email
# 3. When victim later registers with Google OAuth using victim@example.com
# 4. Victim gains access to attacker's pre-created account (or vice versa)
# Test by:
# 1. Register account with victim's email (before they exist)
# 2. Connect OAuth from different email
# 3. Try to access victim's future account
Test 4.3 — Tokenfixatie
# Some implementations allow specifying access_token in request
# or don't properly bind tokens to sessions
# Test: force a known token value
GET /oauth/callback?access_token=KNOWN_VALUE
# If the app accepts and uses this token -> token fixation
Test 4.4 — Verwarring tussen sub-/e-mailclaims
# If an application ties accounts to email (not sub):
# Register malicious OAuth provider with victim's email as their 'email' claim
# Some providers let you set arbitrary email claims
# Test by creating custom OAuth provider with:
{
"sub": "attacker-unique-id",
"email": "victim@example.com",
"email_verified": true
}
Sectie 5: kwetsbaarheden in de autorisatieserver
Test 5.1 — Zwakte in clientauthenticatie
# Confidential clients must authenticate with client_secret
# Test if client_secret is optional:
POST /token
grant_type=authorization_code&
code=CODE&
client_id=CONFIDENTIAL_CLIENT_ID&
# Missing: client_secret
# If this works -> client authentication not enforced
Test 5.2 — Misbruik van device authorization-stroom
# Device flow (for input-constrained devices) can be abused for phishing
POST /device/code
client_id=LEGITIMATE_CLIENT
# Returns user_code that victim enters at verification_uri
# Attacker uses this for social engineering:
# "Enter code XXXX-XXXX at accounts.target.com/activate"
Complete OAuth-testchecklist
- ☐ Breng alle OAuth-stromen en eindpunten in kaart
- ☐ Identificeer client_id, scope-waarden, redirect-URI's
- ☐ Controleer of PKCE is geïmplementeerd
- ☐ Noteer welk type access tokens worden uitgegeven (opaak vs. JWT)
- ☐ Test redirect_uri-parameter — open redirects, path traversal, host-bypass
- ☐ Test state-parameter — aanwezig? gevalideerd? willekeurig? eenmalig bruikbaar?
- ☐ Test scope-manipulatie — vraag ongeautoriseerde scopes aan
- ☐ Test downgrade van response_type (code → token indien implicit ondersteund)
- ☐ Test downgrade van PKCE code_challenge_method
- ☐ Test hergebruik van autorisatiecode (replay na uitwisseling)
- ☐ Test codevervaltijd (codes moeten binnen 60-600 seconden vervallen)
- ☐ Test PKCE-handhaving (uitwisseling zonder code_verifier)
- ☐ Test clientauthenticatie (laat client_secret weg)
- ☐ Test cross-client-code-uitwisseling (gebruik code van client A bij client B)
- ☐ Indien JWT: test algoritmeverwarring, none-algoritme, kid-injectie
- ☐ Test tokenscopehandhaving bij de resource server
- ☐ Test refresh token-rotatie en -intrekking
- ☐ Controleer op tokenlekkage in logs, Referer-headers
- ☐ Test tokenbinding (zijn tokens gekoppeld aan sessies/IP's?)
- ☐ Test OAuth-koppeling zonder e-mailverificatie
- ☐ Test de pre-account-takeover-stroom
- ☐ Test overeenkomst van e-mailclaim vs. sub-claim voor accounts
- ☐ Test ontkoppelingsgedrag (kan een aanvaller de provider van het slachtoffer ontkoppelen?)
OAuth-bugvoorbeelden uit de praktijk
| Bugtype | Platform | Impact | Bounty |
|---|---|---|---|
| redirect_uri-bypass | Account-takeover | $25.000 | |
| Ontbrekende state-parameter | Airbnb | CSRF → ATO | $8.000 |
| Hergebruik van code | Microsoft | Replay-aanval | $15.000 |
| JWT none-algoritme | Auth0 | Authenticatie-bypass | $10.000 |
| E-mailverwarring ATO | Slack | Account-takeover | $20.000 |
| PKCE niet gehandhaafd | Meerdere | Code-onderschepping | $5.000+ |
Testtools
- Burp Suite — Onderschep en wijzig OAuth-stromen; gebruik de OAuth-extensie
- jwt_tool — Uitgebreid JWT-testen (algoritmeverwarring, scannen)
- oidcscan — Geautomatiseerde OpenID Connect-kwetsbaarheidsscanner
- OAuth2 Proxy — Voor het opzetten van testomgevingen
- Postman — Test tokenuitwisselingsstromen met eenvoudige parameterwijziging
De AI-aangedreven scanner van KENSAI test uw OAuth-implementaties automatisch op onderschepping van autorisatiecodes, PKCE-bypass, tokenkwetsbaarheden en account-takeover-scenario's.
Start gratis scan →