OAuth 2.0 redirect_uri हमले: कोड चोरी और Login CSRF
Authorization server की ढीली redirect URI जाँच या पंजीकृत callback पर open redirect से authorization code उजागर हो सकता है। इसका दुरुपयोग code binding और token endpoint की जाँच पर भी निर्भर करता है; login flow का बंधन न होना अलग से login CSRF पैदा कर सकता है।
💡 सरल भाषा में
Authorization server को एक भरोसेमंद डाकघर समझें: वह ऐप के लिए पंजीकृत वापसी पते पर ही एक बार इस्तेमाल होने वाला कोड भेजता है। पता ढीले ढंग से मिलाया जाए या पंजीकृत endpoint आगंतुक को किसी भी साइट पर भेज दे, तो कोड भटक सकता है। कोड मिल जाना अपने आप पहुँच नहीं देता; हमलावर को PKCE और जहाँ आवश्यक हो client authentication सहित token exchange की शर्तें भी पूरी करनी होंगी। अलग login CSRF दोष तब होता है जब साइट यह नहीं जाँचती कि ब्राउज़र ने वही login शुरू किया था जिसे अब पूरा किया जा रहा है।
मुख्य अवधारणाएँ और शब्द
- Authorization Code
- ब्राउज़र redirect से लौटने वाला अल्पकालिक credential। Client इसे token endpoint पर बदलता है; यह client और redirect URI से बँधा होता है, और PKCE होने पर verifier से भी।
redirect_uriका सटीक मिलान- RFC 9700 के अनुसार अनुरोधित URI का पहले से पंजीकृत URI से अक्षरशः मिलान होना चाहिए। Native app के localhost redirect के dynamic port के लिए सीमित अपवाद है।
stateऔर login CSRF- Browser session से बँधे अप्रत्याशित मान को callback पर जाँचने से पुष्टि होती है कि response उपयोगकर्ता द्वारा शुरू किए गए login का है। लागू PKCE भी CSRF सुरक्षा दे सकता है; दोनों का साथ उपयोग defense-in-depth है।
- PKCE (Proof Key for Code Exchange)
- Client एक गुप्त verifier बनाता है और authorization request में उससे निकला challenge भेजता है। Token endpoint code बदलने के लिए verifier माँगता है, जिससे public और confidential clients में code interception का जोखिम घटता है।
Redirect और Login CSRF हमले के चरण
Authorization server असुरक्षित redirect URI स्वीकार करता है
दोषपूर्ण server exact comparison के बजाय wildcard, prefix या substring नियम लगाता है। RFC 9700 native app localhost port के सीमित मामले को छोड़कर exact matching माँगता है।
पंजीकृत endpoint अविश्वसनीय साइट पर भेजता है
स्वीकृत URI client के नियंत्रण वाले open redirect तक पहुँच सकता है, जैसे https://app.example/redirect?next=...। यह ढीली server जाँच को ऐप के अलग CWE-601 दोष के साथ जोड़ता है।
ब्राउज़र redirect के दौरान code ले जाता है
उपयोगकर्ता की अनुमति के बाद server code को स्वीकृत URI पर लौटाता है। Open redirect अनुरोध और code को आगे भेजे तो हमलावर इसे पा सकता है। Code अपने आप bearer access token नहीं है।
Token redemption को भी सफल होना होगा
चुराए गए code के उपयोग के लिए token endpoint की जाँच पास करनी होगी। मूल verifier के बिना PKCE redemption रोकता है; confidential-client authentication और redirect URI का मिलान अतिरिक्त binding देते हैं।
Response binding न होने से login CSRF हो सकता है
यदि callback ऐसे authorization response को स्वीकार करता है जो ब्राउज़र के login प्रयास से जुड़ा नहीं है, तो हमलावर पीड़ित से हमलावर के खाते में login पूरा करवा सकता है। यह account confusion है, पीड़ित के खाते तक स्वतः पहुँच नहीं।
स्रोत कोड: दोषपूर्ण और सुरक्षित कार्यान्वयन
# VULNERABLE: user input is embedded in redirect_uri; state and PKCE are absent.
from urllib.parse import urlencode
from flask import Flask, request, redirect
app = Flask(__name__)
AUTHORIZATION_ENDPOINT = "https://oauth-provider.example/authorize"
@app.route("/auth/login")
def oauth_login():
next_url = request.args.get("next", "")
# The callback is an open redirect, and this URI varies with user input.
redirect_uri = "https://app.example/redirect?next=" + next_url
params = {
"client_id": "example-client",
"response_type": "code",
"redirect_uri": redirect_uri,
}
# Exploitation also requires the authorization server to accept this URI
# under an unsafe wildcard or prefix rule.
return redirect(AUTHORIZATION_ENDPOINT + "?" + urlencode(params))
@app.route("/auth/callback")
def oauth_callback():
# No state check ties this response to the browser's login attempt.
code = request.args.get("code")
return exchange_code_for_tokens(code) # no PKCE verifier provided
# SECURE: fixed registered redirect URI, session-bound state, and PKCE.
import base64
import hashlib
import secrets
from urllib.parse import urlencode
from flask import Flask, request, redirect, session, abort
app = Flask(__name__)
AUTHORIZATION_ENDPOINT = "https://oauth-provider.example/authorize"
REDIRECT_URI = "https://app.example/auth/callback" # exact registered value
CLIENT_ID = "example-client"
@app.route("/auth/login")
def oauth_login():
state = secrets.token_urlsafe(32)
verifier = secrets.token_urlsafe(64)
challenge = base64.urlsafe_b64encode(
hashlib.sha256(verifier.encode("ascii")).digest()
).rstrip(b"=").decode("ascii")
session["oauth_state"] = state
session["pkce_verifier"] = verifier
params = {
"client_id": CLIENT_ID,
"response_type": "code",
"redirect_uri": REDIRECT_URI,
"state": state,
"code_challenge": challenge,
"code_challenge_method": "S256",
}
return redirect(AUTHORIZATION_ENDPOINT + "?" + urlencode(params))
@app.route("/auth/callback")
def oauth_callback():
expected = session.pop("oauth_state", None)
if not expected or not secrets.compare_digest(
request.args.get("state", ""), expected
):
abort(403, "Invalid OAuth state")
code = request.args.get("code")
verifier = session.pop("pkce_verifier", None)
if not code or not verifier:
abort(400, "Missing authorization response")
# The token request must use this exact redirect_uri and verifier.
tokens = exchange_code_for_tokens(
code=code, redirect_uri=REDIRECT_URI, code_verifier=verifier
)
session["user_id"] = tokens["user_id"]
return redirect("/dashboard")
इंजीनियरिंग सुरक्षा जाँच-सूची
- Authorization server में
redirect_uriका पहले से पंजीकृत URI से exact string match लागू करें। केवल RFC 9700 का native-app localhost port अपवाद रखें। - OAuth callback URI में उपयोगकर्ता-नियंत्रित destination न डालें। Callback paths से open redirects हटाएँ और केवल allow-listed स्थानीय route identifiers स्वीकारें।
- हर client type में PKCE S256 के साथ Authorization Code Flow इस्तेमाल करें। Authorization और token requests में वही पंजीकृत
redirect_uriभेजें। - Callback को login प्रयास से बाँधें: session-bound, one-time
stateजाँचें; या CSRF के लिए PKCE पर तभी निर्भर हों जब authorization server PKCE अनिवार्य करता हो। दोनों का उपयोग defense-in-depth है। - चुराया गया authorization code अकेले पर्याप्त नहीं है। Token redemption के लिए सही client authentication और PKCE verifier आवश्यक करें; access token को redirect URL में कभी न रखें।
- Authorization code लॉग न करें। Callback pages पर सख्त
Referrer-Policyलगाएँ और संवेदनशील query parameters हटाने से पहले third-party सामग्री render न करें।