امنیت OAuth چیست؟ آسیبپذیریهای OAuth 2.0 و روشهای پیادهسازی امن
امنیت OAuth مجموعه کنترلهایی است که از فرایند صدور و استفاده از مجوزهای OAuth 2.0 و Tokenهای دسترسی محافظت میکند. ضعف در Redirect URI، PKCE، Scope، Audience، State یا مدیریت Access و Refresh Token میتواند به سرقت Token، دور زدن Authorization یا دسترسی غیرمجاز به API منجر شود. استفاده از Authorization Code همراه با PKCE، اعتبارسنجی دقیق Redirect و Issuer، محدود کردن Tokenها و محافظت در برابر Replay از مهمترین اصول پیادهسازی امن OAuth هستند.
امنیت OAuth به مجموعه کنترلهایی گفته میشود که از فرایند صدور، انتقال، استفاده و تمدید مجوز دسترسی در OAuth 2.0 محافظت میکنند. OAuth به برنامهها اجازه میدهد بدون دریافت مستقیم رمز عبور کاربر، با سطح دسترسی محدود به Resourceهای مشخص دسترسی پیدا کنند؛ اما پیادهسازی نادرست Redirect URI، PKCE، Token، Scope، State، Client Authentication یا Refresh Token میتواند باعث سرقت مجوز، تصاحب Session، دسترسی غیرمجاز به API یا افزایش سطح دسترسی شود.
برای پیادهسازی امن OAuth 2.0 در معماریهای مدرن، Authorization Code Flow همراه با PKCE باید انتخاب اصلی باشد، Redirect URIها باید دقیقاً اعتبارسنجی شوند، Tokenها کوتاهعمر و محدود به Scope و Audience مناسب باشند، Refresh Tokenها در برابر Replay محافظت شوند و Credentialها هرگز در Browser، URL، Log یا Storage ناامن قرار نگیرند. RFC 9700 که Best Current Practice امنیت OAuth 2.0 است، چند الگوی قدیمی از جمله Resource Owner Password Credentials Grant را ناامن اعلام کرده و استفاده از Implicit Grant را نیز بهطور عمومی توصیه نمیکند. 
OAuth 2.0 چیست؟
OAuth 2.0 یک Authorization Framework است.
این نکته ساده، یکی از مهمترین مفاهیم امنیت OAuth محسوب میشود.
OAuth در اصل برای پاسخ به این سؤال طراحی شده است:
«این Application اجازه انجام چه عملیاتی را روی Resourceهای User دارد؟»
نه:
«این User دقیقاً چه کسی است؟»
RFC 6749 توضیح میدهد OAuth به یک Application ثالث اجازه میدهد بدون دریافت Credential اصلی Resource Owner، دسترسی محدود به یک HTTP Service دریافت کند. بهجای اینکه User رمز عبور خود را در اختیار Application ثالث قرار دهد، Authorization Server یک Access Token با ویژگیهایی مانند Scope و Lifetime صادر میکند.
برای مثال فرض کنید یک سرویس ویرایش تصویر نیاز دارد از Cloud Storage کاربر یک تصویر بخواند.
مدل نامناسب این است:
کاربر
↓
نام کاربری و رمز عبور Cloud
↓
برنامه ویرایش تصویر
اما OAuth میتواند چنین مدلی ایجاد کند:
User
↓
Authorization Server
↓
مجوز محدود
↓
Access Token
↓
Image Editor
↓
Cloud API
برنامه ویرایش تصویر رمز عبور اصلی کاربر را نمیبیند.
در عوض Tokenای دریافت میکند که مثلاً فقط اجازه خواندن تصاویر را داشته باشد و بعد از مدت کوتاهی منقضی شود.
این جداسازی یکی از اهداف اساسی OAuth است.
OAuth با Authentication چه تفاوتی دارد؟
OAuth بهتنهایی پروتکل Login نیست.
این اشتباه هنوز در بسیاری از Applicationها دیده میشود.
Authorization میگوید:
چه کاری مجاز است؟
Authentication میگوید:
چه کسی وارد سیستم شده است؟
برای افزودن Identity Layer معمولاً از OpenID Connect یا OIDC روی OAuth 2.0 استفاده میشود.
OWASP نیز OpenID Connect را یک Identity Layer مبتنی بر OAuth 2.0 معرفی میکند که به Client اجازه میدهد هویت End User را براساس Authentication انجامشده توسط Authorization Server بررسی کند.
در OIDC معمولاً ID Token وارد معماری میشود.
بنابراین:
OAuth 2.0
→ Delegated Authorization
در حالی که:
OpenID Connect
→ Authentication / Identity
بر پایه OAuth 2.0
است.
این تفاوت در طراحی امنیتی اهمیت زیادی دارد.
Access Token نباید بدون بررسی قرارداد Provider بهعنوان مدرک هویت User استفاده شود.
اجزای اصلی OAuth 2.0
OAuth 2.0 چند Role اصلی دارد.
RFC 6749 چهار نقش اصلی را تعریف میکند: Resource Owner، Client، Authorization Server و Resource Server.
برای درک سادهتر فرض کنیم یک سایت میخواهد به Google Drive کاربر دسترسی محدود دریافت کند.
| نقش | وظیفه |
|---|---|
| Resource Owner | صاحب داده یا همان User |
| Client | برنامهای که درخواست دسترسی دارد |
| Authorization Server | سرویسی که User را احراز هویت و مجوز را صادر میکند |
| Resource Server | APIای که Resource محافظتشده را ارائه میدهد |
Client ابتدا User را به Authorization Server میفرستد.
User Login و Consent را آنجا انجام میدهد.
Authorization Server سپس مجوز لازم را در قالب Authorization Code یا Token صادر میکند.
Access Token چیست؟
Access Token Credentialای است که Client هنگام درخواست Resource محافظتشده ارائه میکند.
مثلاً:
Client
↓
Access Token
↓
Resource Server
↓
Protected API
Access Token ممکن است Opaque باشد یا ساختارهایی مانند JWT داشته باشد.
مهم این است که Resource Server اعتبار آن را بررسی کند.
RFC 6750 مدل Bearer Token را تعریف میکند.
Bearer Token از نظر امنیتی شبیه «هرکس Token را داشته باشد، امکان استفاده از آن را دارد» است؛ به همین دلیل محافظت در برابر سرقت و Leakage اهمیت بسیار زیادی دارد. RFC 6750 استفاده از TLS و محدود کردن Token به Scope و Recipient مناسب را توصیه میکند.
بنابراین Access Token را نباید مانند یک Identifier ساده دید.
Token یک Credential است.
Refresh Token چیست؟
Access Token بهتر است Lifetime محدودی داشته باشد.
اما User Experience نباید لزوماً کاربر را هر چند دقیقه مجبور به Login مجدد کند.
Refresh Token برای دریافت Access Token جدید استفاده میشود.
مدل کلی:
Access Token
Lifetime کوتاه
↓
منقضی میشود
↓
Refresh Token
↓
Authorization Server
↓
Access Token جدید
Refresh Token معمولاً از Access Token حساستر است، زیرا ممکن است برای مدت طولانی امکان دریافت Tokenهای جدید را فراهم کند.
RFC 9700 تأکید میکند Refresh Token هدف جذابی برای مهاجمان است و در صورت سرقت میتواند برای Mint کردن Access Tokenهای جدید استفاده شود. همچنین برای Public Clientها، Authorization Server باید از Sender-Constrained Refresh Token یا Refresh Token Rotation برای تشخیص Replay استفاده کند.
Authorization Code چیست؟
در Authorization Code Flow، Authorization Server مستقیماً Access Token را از طریق Browser تحویل نمیدهد.
بهجای آن یک Authorization Code موقت ایجاد میشود.
Client سپس Code را از طریق Channel مناسب به Token Endpoint میفرستد و Access Token دریافت میکند.
مدل ساده:
User
↓
Authorization Endpoint
↓
Authorization Code
↓
Client
↓
Token Endpoint
↓
Access Token
این جداسازی باعث میشود Access Token مستقیماً از Front Channel مرورگر عبور نکند.
RFC 6749 نیز Authorization Code Grant را از این جهت دارای مزیت امنیتی میداند که Access Token مستقیماً به Client منتقل میشود و از User Agent عبور نمیکند.
امروزه این Flow معمولاً با PKCE تکمیل میشود. 
PKCE چیست؟
PKCE مخفف Proof Key for Code Exchange است.
RFC 7636 ابتدا PKCE را برای مقابله با Authorization Code Interception در Public Clientها، مخصوصاً Native Applicationها، طراحی کرد.
اما توصیههای امنیتی جدیدتر دامنه استفاده از آن را گسترش دادهاند.
RFC 9700 میگوید Authorization Server باید PKCE را پشتیبانی کند و توصیه PKCE فقط محدود به Mobile App نیست؛ Clientهای دیگر، از جمله Web Applicationها نیز از آن سود میبرند.
PKCE چگونه کار میکند؟
Client برای هر Authorization Transaction یک مقدار تصادفی به نام:
code_verifier
ایجاد میکند.
سپس مشتقی از آن را بهعنوان:
code_challenge
در Authorization Request میفرستد.
پس از دریافت Authorization Code، Client هنگام Token Exchange مقدار اصلی code_verifier را ارائه میدهد.
Authorization Server بررسی میکند:
code_verifier
↓
محاسبه Challenge
↓
مقایسه با code_challenge اولیه
اگر Match نباشد، Code قابل Redeem شدن نیست.
در نتیجه حتی اگر مهاجم Authorization Code را به دست آورد، بدون Verifier مربوط به همان Transaction نمیتواند Token دریافت کند.
S256 در PKCE
PKCE چند روش Challenge دارد، اما Best Current Practice استفاده از S256 است.
RFC 9700 میگوید Client باید از روشی استفاده کند که Verifier را در Authorization Request آشکار نکند و در حال حاضر S256 روش مناسب برای این هدف است.
یعنی:
code_challenge = BASE64URL(SHA256(code_verifier))
نه اینکه خود code_verifier مستقیماً به Front Channel داده شود.
امنیت OAuth در Browser-Based Applications
SPAها و Browser-Based Appها یکی از پیچیدهترین محیطهای OAuth هستند.
چون JavaScript Browser محیطی مشابه Confidential Server Backend برای نگهداری Secret نیست.
در سالهای گذشته Implicit Flow برای Browser Appها رایج بود.
اما وضعیت استانداردها تغییر کرده است.
RFC 10017 که Best Current Practice جدید برای Browser-Based Applications است، توضیح میدهد امروزه Authorization Code Flow همراه با PKCE روش توصیهشده برای Applicationهای Browser-Based محسوب میشود. یکی از دلایل اصلی کنار گذاشتن Implicit Flow، ریسکهای ناشی از قرار گرفتن Access Token در Front Channel و URL است.
بنابراین در طراحی جدید:
Browser App
↓
Authorization Code + PKCE
بهتر از:
Implicit Flow
↓
Access Token در Front Channel
است.
چرا Implicit Flow دیگر توصیه نمیشود؟
Implicit Grant در RFC اولیه OAuth برای برنامههای JavaScript طراحی شده بود.
اما تجربه عملی سالهای بعد نشان داد ارسال Access Token در Authorization Response باعث ایجاد Attack Surfaceهای مهمی میشود.
RFC 9700 بیان میکند Implicit Grant و سایر Response Typeهایی که Access Token را مستقیماً در Authorization Response صادر میکنند، در برابر Token Leakage و Replay آسیبپذیرند و Clientها بهطور کلی نباید از آن استفاده کنند مگر در شرایط خاص با Mitigationهای مناسب.
از سوی دیگر Browserهای امروزی امکان استفاده از Authorization Code + PKCE و CORS را فراهم کردهاند.
در نتیجه دلیل تاریخی استفاده از Implicit Flow تا حد زیادی از بین رفته است.
Resource Owner Password Credentials Grant چرا ناامن است؟
یکی از مهمترین تغییرات توصیههای جدید OAuth مربوط به Password Grant یا ROPC است.
در این Flow، User Credential خود را مستقیماً به Client میدهد.
مثلاً:
Username
Password
↓
OAuth Client
↓
Authorization Server
این طراحی دقیقاً بخشی از مزیت اصلی OAuth را از بین میبرد.
RFC 9700 بهصراحت اعلام میکند Resource Owner Password Credentials Grant نباید استفاده شود؛ زیرا Credential کاربر را در معرض Client قرار میدهد، Attack Surface را افزایش میدهد و با Authenticationهای مدرن مانند MFA و WebAuthn نیز سازگاری مناسبی ندارد.
پس برای Application جدید:
Password Grant
نباید انتخاب شود.
Client Credentials Grant چه زمانی مناسب است؟
همه OAuth Flowها User ندارند.
در ارتباط Service-to-Service ممکن است یک Application بخواهد با Identity خودش به Resource دسترسی پیدا کند.
مثلاً:
Reporting Service
↓
Client Credentials
↓
Authorization Server
↓
Access Token
↓
Internal API
در این Flow Resource Owner انسانی وجود ندارد.
اما Scope و Audience همچنان باید حداقلی باشند.
یک Service نباید فقط به دلیل داشتن Client Credential به تمام APIهای Organization دسترسی پیدا کند. 
آسیبپذیری Redirect URI در OAuth
Redirect URI یکی از حساسترین بخشهای OAuth است.
Authorization Server پس از پایان Authorization User را به Redirect URI ثبتشده برای Client برمیگرداند.
اگر Redirect Validation ضعیف باشد، Credentialهای OAuth ممکن است به مقصد ناخواسته ارسال شوند.
RFC 9700 الزام میکند Redirect URI ثبتشده و Redirect URI دریافتشده با Exact String Matching مقایسه شوند، بهجز استثنای Port مربوط به localhost برای Native Appها. این کنترل برای جلوگیری از نشت Authorization Code و Token اهمیت دارد.
چرا Wildcard خطرناک است؟
فرض کنیم Client این Pattern را ثبت کند:
https://example.com/*
اگر Authorization Server هر Path یا Subdomain مرتبط را قبول کند، ممکن است Redirect نهایی به Endpointی برسد که:
Open Redirect دارد،
تحت کنترل Component دیگری است،
یا Security Boundary متفاوتی دارد.
روش مناسب ثبت URIهای مشخص است.
مثلاً:
https://example.com/oauth/callback
و Match باید دقیق انجام شود.
Open Redirect و OAuth
Open Redirect به تنهایی یک Vulnerability متفاوت است، اما در OAuth میتواند Impact بیشتری پیدا کند.
فرض کنید Redirect URI مجاز به Endpointی ختم شود که خودش URL مقصد دیگری را از Query Parameter میگیرد.
در چنین شرایطی Authorization Code ممکن است ابتدا به Domain Client برسد و سپس Browser به Domain دیگری Redirect شود.
RFC 9700 روی اعتبارسنجی دقیق Redirect URI تأکید میکند تا Credentialهای Authorization Flow به Locationهای ناخواسته منتقل نشوند.
بنابراین Client نیز نباید روی OAuth Callback خود Open Redirect داشته باشد.
CSRF در OAuth چیست؟
Cross-Site Request Forgery در OAuth میتواند باعث شود Authorization Response متعلق به یک Transaction اشتباه وارد Session قربانی شود.
یکی از Controlهای شناختهشده OAuth پارامتر:
state
است.
Client یک مقدار تصادفی و وابسته به Session ایجاد میکند.
آن را در Authorization Request قرار میدهد.
سپس هنگام Callback مقدار برگشتی را بررسی میکند.
اگر State با Transaction اولیه Match نکند، Response باید Reject شود.
اما توصیههای جدید OAuth نکته مهمی دارند: PKCE نیز وقتی درست اجرا شده و پشتیبانی Authorization Server قطعی باشد، میتواند Protection قوی در برابر Authorization Code Injection و برخی CSRF Scenarioها ایجاد کند. اگر PKCE قابل اتکا نیست، state یا در OpenID Connect، nonce باید بهدرستی استفاده شود.
اشتباه رایج در State
وجود state بهتنهایی امنیت ایجاد نمیکند.
State باید:
Transaction-Specific باشد،
غیرقابل حدس باشد،
به Browser Session مربوط متصل شود،
و پس از Callback Validate شود.
استفاده از مقدار ثابت مانند:
state=123
تقریباً Protection واقعی ایجاد نمیکند.
همچنین اگر Application Data داخل State قرار دهد، Integrity آن باید محافظت شود.
RFC 9700 توصیه میکند در صورت حساس بودن محتوای State، آن را به Session Bind کرده یا با مکانیزم مناسب در برابر Tampering محافظت کنید.
Authorization Code Injection چیست؟
در Code Injection مهاجم تلاش میکند Authorization Code متعلق به Context دیگری را وارد OAuth Session Client کند.
هدف ممکن است این باشد که Client به اشتباه Session خود را به Identity یا Resource متعلق به Transaction دیگری Bind کند.
RFC 9700 این Attack را بهصورت مستقل بررسی کرده و PKCE را یکی از اصلیترین Countermeasureها معرفی میکند. PKCE Code را به Client Instance و Transaction مرتبط میکند؛ بنابراین Verifier نامرتبط باعث Fail شدن Token Exchange میشود.
Authorization Code Interception
Authorization Code ممکن است در مسیرهای مختلف افشا شود.
خصوصاً در Native Appها، Redirect گاهی از طریق Custom URI Scheme انجام میشود.
Application دیگری روی Device ممکن است تلاش کند Redirect را دریافت کند.
RFC 7636 دقیقاً برای کاهش این خطر PKCE را معرفی کرد. Authorization Code بدون Code Verifier مربوط به Transaction ارزش بسیار کمتری برای مهاجم خواهد داشت.
امنیت OAuth در Mobile و Native Apps
Native App نمیتواند یک client_secret عمومی را Secret واقعی فرض کند.
اگر Secret داخل APK، IPA یا Binary Application قرار داشته باشد، User دستگاه میتواند به Application Package دسترسی داشته باشد.
RFC 6749 نیز Public Native Clientها را از Clientهای Confidential متمایز میکند و RFC 8252 برای Native Appها PKCE را الزامی میداند.
External Browser بهجای Embedded WebView
RFC 8252 توصیه میکند Authorization Request در Native App از External User-Agent، معمولاً System Browser، استفاده کند.
دلیل آن این است که Embedded WebView Trust Boundary را ضعیف میکند.
Application میزبان ممکن است:
Credential را مشاهده کند،
Cookie را تحت تأثیر قرار دهد،
UI جعلی نمایش دهد،
یا تعامل Authentication را Manipulate کند.
External Browser Separation بهتری ایجاد میکند.
Client Secret چیست؟
Confidential Clientهایی مانند Server-Side Web App ممکن است Client Credential داشته باشند.
اما Client Secret باید واقعاً Secret بماند.
نباید در:
Frontend JavaScript،
Mobile Application،
Public Repository،
HTML،
Browser Storage
قرار گیرد.
Public Client اصولاً نمیتواند Secret مشترکی را بهشکلی قابل اعتماد از End User پنهان کند.
بنابراین قرار دادن یک String ثابت با نام client_secret در SPA آن Application را Confidential نمیکند. 
خطر افشای Access Token
Token Leakage میتواند از مسیرهای مختلف رخ دهد:
Browser History،
URL،
Referer Header،
Application Log،
Analytics،
XSS،
Crash Report،
Proxy Log،
Storage ناامن.
به همین دلیل Access Token نباید در Query String URL ارسال شود.
RFC 9700 بهصراحت میگوید Client نباید Access Token را به روشی که RFC 6750 برای URI Query تعریف کرده بود، داخل URI Query Parameter ارسال کند.
روش معمول:
Authorization: Bearer <token>
است.
Token در LocalStorage؛ آیا امن است؟
این سؤال پاسخ مطلق ندارد، زیرا Architecture اهمیت دارد.
اما LocalStorage توسط JavaScript همان Origin قابل خواندن است.
بنابراین در صورت XSS، Token ذخیرهشده در LocalStorage میتواند در معرض دسترسی Script مخرب قرار بگیرد.
Browser-Based OAuth Architecture باید Threat Model مشخصی برای Token Storage داشته باشد.
RFC 10017 برای Browser-Based Applications چند Architecture مختلف را بررسی میکند و تأکید دارد Applicationهای Browser-Based Public Client هستند و Secure Storage آنها محدودیتهای خاص خود را دارد.
برای Applicationهای حساس، الگوهایی مانند Backend for Frontend یا BFF میتوانند باعث شوند Tokenهای اصلی در Server-Side Component باقی بمانند و مستقیماً در JavaScript قرار نگیرند.
XSS چرا برای OAuth بسیار خطرناک است؟
XSS در یک OAuth Client مرورگری میتواند بسیاری از Protectionهای سطح Protocol را دور بزند.
Script مخرب ممکن است:
Token را بخواند،
Authorization Request ایجاد کند،
API را از Context User فراخوانی کند،
یا داده Session را سرقت کند.
حتی DPoP نیز XSS را بهصورت کامل حل نمیکند، زیرا Script اجراشده در Context Client ممکن است بتواند از Key Material یا APIهای مرتبط در همان Runtime استفاده کند. RFC 9449 نیز محدودیتهای DPoP در حضور Compromise Client یا XSS را مطرح میکند.
بنابراین OAuth Security جای Secure Coding Browser را نمیگیرد.
CSP، Output Encoding، Dependency Security و جلوگیری از XSS همچنان حیاتی هستند.
Bearer Token و Replay Attack
Bearer Token یک مشکل ذاتی دارد:
اگر Token سرقت شود، مهاجم ممکن است بتواند آن را Replay کند.
راهکار اصلی جلوگیری از Leakage است.
اما در سیستمهای حساس میتوان علاوه بر آن از Sender-Constrained Token استفاده کرد.
RFC 9700 دو روش مهم را معرفی میکند:
mTLS طبق RFC 8705،
و DPoP طبق RFC 9449.
DPoP چیست؟
DPoP یا Demonstrating Proof of Possession یک مکانیزم Application-Level برای Bind کردن Token به یک Key Pair است.
Client هنگام Request یک Proof امضاشده تولید میکند.
Authorization Server Token را به Public Key مربوط Bind میکند.
Resource Server سپس بررسی میکند Client ارائهکننده Token واقعاً Private Key متناظر را در اختیار دارد.
RFC 9449 هدف DPoP را کاهش امکان Replay Token سرقتشده بیان میکند.
مدل ساده:
Access Token
+
Client Private Key Proof
↓
Resource Server
بنابراین داشتن Access Token بهتنهایی کافی نیست.
البته DPoP جای HTTPS، Authorization یا Client Authentication را نمیگیرد.
mTLS و OAuth
روش دیگر Sender-Constraining استفاده از Mutual TLS است.
RFC 8705 مکانیزمی برای Client Authentication با Certificate و همچنین Certificate-Bound Access Token تعریف میکند.
این مدل بیشتر در محیطهای Enterprise، Financial API و Server-to-Server قابل استفاده است.
Client با Certificate مشخص Authenticate میشود و Token میتواند به همان Certificate Bind شود.
در نتیجه Token سرقتشده بدون Certificate مربوط قابل استفاده نخواهد بود.
Scope چیست؟
Scope مشخص میکند Client چه دسترسیهایی درخواست میکند.
مثلاً:
profile.read
files.read
files.write
payments.create
یکی از اصول مهم امنیت OAuth Least Privilege است.
اگر Client فقط نیاز به خواندن Profile دارد، نباید Tokenای با Permission حذف Account یا انجام Payment دریافت کند.
RFC 9700 توصیه میکند Privilegeهای Access Token به حداقل موردنیاز Application و Use Case محدود شوند.
Scope بهتنهایی کافی نیست
Scope ممکن است نسبتاً Broad باشد.
مثلاً:
files.read
اما User شاید فقط اجازه دسترسی به Folder مشخصی را داده باشد.
Resource Server باید علاوه بر Scope، Authorization واقعی Resource را نیز بررسی کند.
Token با Scope مناسب نباید به معنای:
Access to every object
باشد.
Authorization Context، User Ownership و Policy Resource همچنان اهمیت دارند.
Audience چیست؟
Audience مشخص میکند Token برای کدام Resource Server صادر شده است.
فرض کنید Organization دو API دارد:
https://billing.example
https://profile.example
Token صادرشده برای Profile API نباید در Billing API پذیرفته شود.
RFC 9700 توصیه میکند Access Token تا حد امکان Audience-Restricted باشد و Resource Server در هر Request بررسی کند Token واقعاً برای همان Server صادر شده است.
این کنترل اثر Token Leakage را کاهش میدهد.
Mix-Up Attack چیست؟
Mix-Up Attack در Clientهایی اهمیت دارد که با چند Authorization Server کار میکنند.
مثلاً Application Login از چند Identity Provider پشتیبانی میکند.
Client باید بداند Authorization Response واقعاً از کدام Authorization Server آمده است.
اگر این Identity اشتباه شود، Credential یا Authorization Code ممکن است به Endpoint اشتباه ارسال شود.
RFC 9207 پارامتر iss را برای شناسایی صریح Authorization Server در Authorization Response تعریف کرده و آن را Countermeasure مؤثر Mix-Up Attack معرفی میکند.
Client باید iss را با Issuer مورد انتظار مقایسه کند و در صورت اختلاف Response را Reject کند.
چرا Endpoint Discovery باید امن باشد؟
OAuth Provider ممکن است Metadata منتشر کند.
Client میتواند از Metadata مواردی مانند:
Authorization Endpoint،
Token Endpoint،
Supported PKCE Method
را دریافت کند.
RFC 9700 توصیه میکند Authorization Server Metadata براساس RFC 8414 منتشر شود و Client در صورت وجود از آن استفاده کند.
اما Metadata نیز Trust Boundary دارد.
Issuer باید از Configuration یا Source معتبر انتخاب شود.
Client نباید URL کاملاً Arbitrary User را گرفته و Metadata و Endpointهای امنیتی خود را از آن بسازد.
Open Redirect در Authorization Server
خود Authorization Server نیز نباید Open Redirector داشته باشد.
OWASP OAuth Cheat Sheet تأکید میکند Client و Authorization Server نباید Endpointهایی داشته باشند که Browser را براساس Query Parameter آزاد به URI Arbitrary Forward کنند؛ زیرا این رفتار میتواند به Exfiltration Authorization Code یا Token کمک کند.
Redirect Target باید محدود باشد.
Refresh Token Rotation
Refresh Token Rotation یکی از مهمترین کنترلها برای Public Client است.
در این مدل با هر Refresh:
Refresh Token A
↓
Access Token جدید
+
Refresh Token B
صادر میشود و Token قبلی دیگر معتبر نیست.
Server رابطه میان Tokenهای یک Grant را نگه میدارد.
اگر Token قبلی دوباره استفاده شود، احتمال Replay مطرح است.
RFC 9700 توضیح میدهد Authorization Server برای Public Client باید از Sender-Constrained Refresh Token یا Rotation استفاده کند تا Replay قابل تشخیص باشد.
Refresh Token نباید عمر نامحدود داشته باشد
Refresh Token طولانیعمر میتواند User Experience خوبی ایجاد کند، اما Risk نیز افزایش میدهد.
RFC 9700 توصیه میکند Refresh Token در صورت Inactivity پس از مدت مناسب Expire شود و Server میتواند در Security Eventهایی مانند Password Change یا Logout آن را Revocation کند.
Lifetime باید متناسب با حساسیت Application باشد.
بانک و یک سایت عمومی لزوماً Policy یکسانی ندارند.
Token Revocation
کاربر باید بتواند دسترسی Client را پس بگیرد.
Application نیز باید برای رویدادهای امنیتی امکان Revocation Token یا Grant را داشته باشد.
نمونه شرایط:
Account Compromise،
Device Lost،
Password Change،
Logout از تمام Sessionها،
حذف Integration،
تشخیص Refresh Token Replay.
فقط انتظار برای Expire شدن Token همیشه کافی نیست.
Token Introspection
Opaque Token را Resource Server نمیتواند الزاماً بهصورت محلی Decode کند.
در چنین معماریای ممکن است از Introspection Endpoint برای بررسی وضعیت Token استفاده شود.
Resource Server میتواند بداند Token:
Active است یا نه،
Scope چیست،
برای چه Client یا Subjectی صادر شده،
چه زمانی Expire میشود.
اما Introspection Endpoint خودش یک Security-Sensitive Endpoint است و باید Authentication و Authorization مناسب داشته باشد.
JWT Access Token و اشتباهات رایج
JWT یک Container Format است، نه تضمین امنیت.
وقتی Access Token از JWT استفاده میکند، Resource Server باید مواردی مانند:
Signature،
Algorithm،
Issuer،
Audience،
Expiration،
و Claimهای موردنیاز
را بررسی کند.
صرف Decode کردن JWT و خواندن Payload Authentication نیست.
یک Anti-Pattern خطرناک:
decode(token)
→ trust claims
است.
در حالی که باید:
parse
↓
cryptographic validation
↓
issuer validation
↓
audience validation
↓
time validation
↓
authorization
انجام شود.
تفاوت ID Token و Access Token
در OpenID Connect دو Token ممکن است همزمان وجود داشته باشند:
ID Token،
Access Token.
ID Token برای Client است تا اطلاعات Authentication User را بررسی کند.
Access Token برای Resource Server است تا API Access را کنترل کند.
Client نباید Access Token را بهجای ID Token برای Login Logic استفاده کند مگر Provider Contract صراحتاً چنین Semanticsای تعریف کرده باشد.
Resource Server نیز نباید صرفاً هر ID Token را بهعنوان Access Token قبول کند.
هر Token Audience و Purpose خودش را دارد.
Token Confusion
اگر چند نوع JWT در یک Ecosystem استفاده شوند، Resource Server باید بتواند Purpose آنها را تشخیص دهد.
مثلاً:
ID Token،
Access Token،
Logout Token،
Client Assertion.
اگر همه JWTها Signature معتبر از یک Issuer داشته باشند ولی Audience و Type بهدرستی بررسی نشود، ممکن است Token مخصوص یک Context در Context دیگری پذیرفته شود.
Secure Validation باید علاوه بر Signature، Semantics Token را نیز بررسی کند.
Client Authentication
Confidential Client باید هنگام تعامل با Authorization Server Authenticate شود.
RFC 9700 توصیه میکند در صورت امکان Authorization Server Client Authentication را enforce کند.
روشهای مختلفی وجود دارند:
Shared Secret،
private_key_jwt،
mTLS.
برای سیستم حساس، روشهای مبتنی بر Key Pair میتوانند مزایای امنیتی بیشتری نسبت به Secret ثابت داشته باشند.
اما انتخاب روش باید با Capability Provider و Threat Model هماهنگ باشد.
Client Secret Rotation
Secretهای ثابت نباید سالها بدون تغییر باقی بمانند.
Infrastructure باید امکان:
Rotation،
Overlap کوتاه برای Migration،
Revocation فوری،
Audit
را داشته باشد.
همچنین Secret نباید در Source Repository Hardcode شود.
استفاده از Secret Manager و Access Policy محدود مناسبتر است.
Pushed Authorization Requests یا PAR چیست؟
در Flow معمولی بسیاری از Authorization Parameterها از طریق Browser به Authorization Endpoint میروند.
PAR یا Pushed Authorization Requests طبق RFC 9126 به Client اجازه میدهد Authorization Request را ابتدا از یک Channel مستقیم به Authorization Server Push کند و سپس یک request_uri دریافت کند که Browser از آن استفاده میکند.
این مدل میتواند Attack Surface دستکاری Authorization Parameterهای Front Channel را کاهش دهد.
PAR مخصوصاً در Security Profileهای حساس و Financial APIها اهمیت پیدا میکند.
امنیت Scope در Authorization Request
مهاجم نباید بتواند Scope درخواست را بین Client و Authorization Server افزایش دهد.
Authorization Server نیز نباید صرفاً هر Scope درخواستشده را صادر کند.
Scope باید در Intersection موارد زیر باشد:
Scopeهای ثبتشده Client
∩
Scopeهای مجاز Policy
∩
Scopeهای Consentشده User
اگر Client درخواست profile.read دارد، نباید فقط با تغییر Parameter بتواند admin.write دریافت کند.
Consent Screen
Consent Screen نباید یک صفحه نمایشی بدون Enforcement باشد.
Authorization Server باید دقیقاً Scopeهایی را صادر کند که User پذیرفته است.
UI باید Scope را قابلفهم نمایش دهد.
استفاده از عبارتهای مبهم مانند:
Allow access
بدون توضیح Scope ممکن است User را نسبت به سطح دسترسی واقعی گمراه کند.
Security و UX در این بخش به هم مرتبطاند.
Clickjacking روی Authorization Endpoint
Authorization Endpoint صفحهای بسیار حساس است.
اگر Attacker بتواند Consent یا Login UI را داخل Frame پنهان قرار دهد، ممکن است Social Engineering یا Clickjacking ایجاد شود.
Authorization Server باید Policyهای مناسب Frame Embedding داشته باشد.
مثلاً با CSP frame-ancestors یا کنترلهای معادل، بسته به معماری.
این مورد Root Cause مستقلی از OAuth دارد اما اثر آن میتواند Authorization را تحت تأثیر قرار دهد.
Phishing و OAuth Consent
گاهی مهاجم اصلاً Protocol را نمیشکند.
یک OAuth Client مخرب ثبت میکند.
سپس User را متقاعد میکند Scopeهای قدرتمند به آن بدهد.
Authorization Server باید:
Client Registration Policy،
Consent UX،
Risk Detection،
و Scope Governance
مناسب داشته باشد.
در Enterprise Environment همچنین Admin Consent باید با حساسیت کنترل شود.
Dynamic Client Registration
در سیستمهایی که Client Registration بهصورت Dynamic انجام میشود، Policy ثبت Client اهمیت زیادی دارد.
Redirect URI،
Client Metadata،
Logo URL،
Contact Information،
و سایر Propertyها نباید به Vectorهای جدید تبدیل شوند.
Dynamic Registration نباید به هر Anonymous Actor اجازه دهد Clientهایی با Identity فریبنده ایجاد کند، مگر اینکه Business Model و Security Control برای آن طراحی شده باشد.
امنیت Redirect در Mobile App
Native App ممکن است Custom URI Scheme داشته باشد:
myapp://oauth/callback
مشکل این است که App دیگری ممکن است بتواند همان Scheme را Claim کند.
RFC 8252 چند Redirect Pattern برای Native Appها بررسی میکند و PKCE را برای Public Native Clientها الزامی میداند تا Authorization Code سرقتشده بدون Verifier قابل Redeem نباشد.
در Platformهایی که App-claimed HTTPS URI یا Universal Link/App Link پشتیبانی میشود، استفاده صحیح از آنها میتواند Ownership Redirect را بهتر اثبات کند.
Loopback Redirect برای Desktop Apps
بعضی Desktop Appها یک Local HTTP Listener موقت باز میکنند.
مثلاً Browser به:
http://127.0.0.1:<random-port>/callback
Redirect میشود.
RFC 9700 در Exact Redirect Matching برای Loopback Native Appها استثنای Port را در نظر میگیرد، زیرا App ممکن است Port تصادفی Runtime انتخاب کند.
اما Host و Path همچنان باید مطابق Profile امن باشند.
OAuth Mix-Up در چند Provider
فرض کنید سایت Login با سه Provider دارد:
Provider A
Provider B
Provider C
Client باید Transaction State را به Provider انتخابشده Bind کند.
Authorization Response نباید بتواند Client را درباره Issuer گمراه کند.
استفاده از iss طبق RFC 9207 راهکار استاندارد مؤثری است.
اگر Provider آن را پشتیبانی نمیکند، Architecture باید Countermeasure جایگزین معتبر داشته باشد؛ مثلاً Redirect URIهای متمایز، مطابق شرایط Security BCP.
Token Replay در Resource Server
Resource Server نباید فقط بررسی کند Token Signature معتبر است.
باید بررسی شود:
Audience درست است؟
Scope Action را اجازه میدهد؟
Token Expire نشده؟
Issuer مورد انتظار است؟
Sender Constraint در صورت استفاده صحیح است؟
User یا Client هنوز Permission دارد؟
OAuth Authentication Layer نباید Authorization Business-Level را حذف کند.
امنیت Logout در OAuth و OIDC
Logout پیچیدهتر از حذف یک Cookie Client است.
ممکن است Sessionهای مختلفی وجود داشته باشند:
Client Session،
Authorization Server Session،
Refresh Token،
Access Token.
Logout Policy باید مشخص کند کدامها Revoked میشوند.
برای Application حساس شاید Logout باید Refresh Token را Invalid کند.
برای SSO Environment ممکن است Sign-out فقط Local Client باشد.
این تصمیم باید صریح طراحی شود.
OAuth و CSRF در Login
Login CSRF یکی از حالتهای مهم است.
در این سناریو ممکن است قربانی ناخواسته وارد Client با Account مهاجم شود.
سپس اطلاعاتی که قربانی تصور میکند وارد Account خودش کرده، در Account مهاجم ذخیره شوند.
PKCE، State و Transaction Binding درست میتوانند چنین Attackهایی را کاهش دهند.
وجود OAuth Login به معنی حذف نیاز به CSRF Threat Modeling نیست.
SameSite Cookie و OAuth
OAuth Redirect Flow به Cross-Site Navigation وابسته است.
بنابراین تنظیم Cookie باید با Workflow واقعی سازگار باشد.
استفاده نادرست از SameSite=Strict ممکن است Flow را خراب کند.
استفاده بیش از حد باز از Cookie نیز Riskهای خودش را دارد.
Session Cookie بهتر است حداقل:
Secure،
HttpOnly،
و SameSite مناسب Threat Model
داشته باشد.
انتخاب Lax، Strict یا None باید براساس Flow و Browser Behavior انجام شود.
CORS و OAuth
CORS جای OAuth Security را نمیگیرد.
Token Endpoint در بعضی Browser-Based Architectureها باید CORS مناسب داشته باشد.
اما CORS Policy بیش از حد باز میتواند Attack Surface Browser را افزایش دهد.
Originهای مجاز باید مشخص باشند.
Resource Server نیز نباید فرض کند چون Browser CORS را enforce میکند، Authorization در Backend لازم نیست.
Non-Browser Client به CORS محدود نیست.
HTTPS اجباری است
OAuth Credentialها نباید روی HTTP ساده منتقل شوند.
Access Token، Authorization Code و Refresh Token همگی Credential Security-Sensitive هستند.
RFC 6750 TLS را برای محافظت Bearer Token در Transit الزامی میداند.
Redirect URIهای Web نیز باید HTTPS باشند، مگر استثناهای محدود استاندارد برای Native Loopback.
TLS Validation نباید غیرفعال شود.
Token را در Log ذخیره نکنید
Logging کامل Request Header میتواند:
Authorization: Bearer ...
را ثبت کند.
همین موضوع درباره Query String، Error Dump و Debug Trace نیز صدق میکند.
Application، Reverse Proxy، APM و SIEM Pipeline باید Token Redaction داشته باشند.
مثلاً:
Authorization: Bearer [REDACTED]
بهتر از ذخیره Credential واقعی است.
OAuth و Browser History
Authorization Code و خصوصاً Access Token نباید بیدلیل در Browser History باقی بمانند.
RFC 9700 ریسک Leakage Credential از Browser History و URL را بررسی میکند و استفاده از Access Token در URI Query را ممنوع میداند.
Callback Page نیز بهتر است پس از پردازش Code، URL را Clean کند یا User را به Page جدید هدایت کند.
Referer Leakage
اگر Credential یا Sensitive Parameter در URL باشد، Browser ممکن است تحت شرایطی URL را از طریق Referer به Resource دیگر منتقل کند.
به همین دلیل بهتر است Callback Page Resourceهای Third-Party غیرضروری نداشته باشد.
Referrer Policy میتواند لایه مکمل باشد.
اما Root Solution همچنان عدم قرار دادن Access Token در URL است.
Client باید Authorization Code را یکبار مصرف بداند
Authorization Code باید Lifetime کوتاه و Single Use باشد.
اگر Code دوباره Redeem شود، Authorization Server باید آن را Reject کند.
این کنترل احتمال Replay را کاهش میدهد.
PKCE نیز Code را به Transaction مربوط Bind میکند.
ترکیب این دو Defense in Depth بهتری ایجاد میکند.
امنیت Token Endpoint
Token Endpoint یکی از حساسترین Endpointهای Authorization Server است.
باید:
فقط HTTPS باشد،
Grant را Validate کند،
Client را در صورت نیاز Authenticate کند،
PKCE را enforce کند،
Redirect URI Binding را بررسی کند،
Grant Type مجاز Client را کنترل کند،
و Errorها را بدون افشای Secret برگرداند.
Rate Limit نیز برای Abuse و Brute Force برخی Credentialها مفید است.
Security Header روی Authorization Server
Authorization UI شامل Login و Consent است.
بنابراین Secure Headerهایی مانند:
CSP،
Frame Protection،
Secure Cookie Configuration،
HSTS
میتوانند مهم باشند.
اما این Headerها جای Protocol Validation مانند PKCE و Redirect URI Check را نمیگیرند.
Error Handling امن
Error Response نباید Token، Client Secret، Code Verifier یا Internal Configuration را Log یا نمایش دهد.
User نیاز ندارد بداند:
Database Query چه بوده،
Token Signature چرا Fail شده،
Private Key کجا ذخیره شده،
یا Client Secret چه Prefixی دارد.
Security Detail باید فقط در Log داخلی و Sanitized ثبت شود.
OAuth در WordPress
WordPress Core بهصورت پیشفرض یک Authorization Server عمومی OAuth 2.0 برای تمام Use Caseها محسوب نمیشود، اما Pluginها و Integrationهای زیادی میتوانند OAuth Client یا Authorization Layer اضافه کنند.
خطر اصلی معمولاً در Plugin سفارشی یا Integration رخ میدهد.
موارد مهم Code Review:
Redirect URI،
State،
PKCE،
Token Storage،
Callback Handler،
Scope،
Nonce در OIDC،
Client Secret Storage،
Refresh Token Handling.
اگر Plugin Login with Google یا Provider دیگری اضافه میکند، نباید فقط وجود پارامترهای Callback را بهعنوان Login موفق قبول کند.
Token و Issuer باید طبق Protocol و Provider Documentation اعتبارسنجی شوند.
OAuth و WooCommerce
WooCommerce Integrationها ممکن است OAuth یا OIDC را برای:
Payment Provider،
CRM،
Shipping،
Accounting،
Marketplace
استفاده کنند.
Tokenهای Integration معمولاً دسترسی مالی یا Order Data دارند.
بنابراین Scope باید حداقل باشد.
Refresh Token نباید در Option عمومی، Frontend JavaScript یا Log ذخیره شود.
Callbackهای OAuth نیز باید State و PKCE یا سایر Transaction Bindingها را درست Validate کنند.
تست امنیت OAuth چگونه انجام شود؟
تست OAuth باید در Environment مجاز انجام شود.
هدف اثبات ضعف Protocol یا Configuration است، نه سرقت Token واقعی User.
ابتدا معماری Flow مستند میشود:
Authorization Server چیست؟
Client Public است یا Confidential؟
Grant Type چیست؟
Redirect URI کدام است؟
PKCE فعال است؟
چه Scopeهایی صادر میشوند؟
Refresh Token وجود دارد؟
Resource Server چگونه Token را Validate میکند؟
بعد هر Trust Boundary جداگانه بررسی میشود.
بررسی Redirect URI
تست دفاعی باید بررسی کند Authorization Server فقط URIهای ثبتشده را قبول میکند.
Variationهایی که نباید پذیرفته شوند باید Reject شوند.
هدف یافتن Misconfiguration است، نه Redirect کردن Credential واقعی به Server مهاجم.
از URI آزمایشی در Staging استفاده کنید.
بررسی PKCE
موارد مهم:
Flow بدون code_challenge پذیرفته میشود یا نه؟
S256 پشتیبانی میشود؟
Code بدون Verifier قابل Redeem است؟
Verifier اشتباه Reject میشود؟
Code Challenge واقعاً به Code Bind شده است؟
RFC 9700 تأکید میکند Authorization Server باید Correct Usage code_verifier را enforce کرده و از PKCE Downgrade جلوگیری کند.
بررسی State
State باید برای هر Transaction جدید تغییر کند.
State Transaction A نباید روی Transaction B پذیرفته شود.
State حذفشده یا تغییرکرده باید Flow را Fail کند، مگر Client بهصورت استاندارد و آگاهانه از PKCE یا OIDC Nonce بهعنوان Countermeasure مربوط استفاده کند.
Testing باید با Architecture واقعی هماهنگ باشد.
بررسی Scope
Tester باید Scopeهای Expected را مشخص کند.
سپس بررسی شود آیا Client یا User میتواند Scope خارج از Policy دریافت کند.
Resource Server نیز باید Scope را واقعاً enforce کند.
وجود Claim scope در Token بدون بررسی آن در API هیچ امنیتی ایجاد نمیکند.
بررسی Audience
Token صادرشده برای API A نباید روی API B قابل استفاده باشد.
اگر Resource Server هر Token امضاشده توسط Issuer را بدون Audience Check قبول کند، Token Confusion یا Cross-Service Replay ممکن است ایجاد شود.
RFC 9700 Audience Restriction را برای کاهش Impact Token Leakage توصیه میکند.
بررسی Refresh Token
در Public Client باید مشخص شود:
Rotation فعال است؟
یا Sender Constraint؟
Refresh Token قبلی بعد از Rotation چه میشود؟
Replay تشخیص داده میشود؟
Token بعد از Logout یا Security Event چه وضعیتی دارد؟
Token Inactivity Expiration وجود دارد؟
این موارد بخشی از Best Current Practice هستند.
بررسی Multi-Provider
اگر Client با چند Authorization Server کار میکند، Mix-Up باید در Threat Model باشد.
iss باید در صورت پشتیبانی Validate شود.
Client نباید Token Endpoint Provider را فقط از Data برگشتی غیرقابلاعتماد انتخاب کند.
Issuer، Metadata و Endpointها باید رابطه Trust مشخص داشته باشند.
SAST و OAuth
Static Analysis میتواند Anti-Patternهایی مانند:
Client Secret در Source،
Disable TLS Validation،
عدم بررسی State،
Redirect URI آزاد،
Decode JWT بدون Verify،
Token Logging
را پیدا کند.
اما OAuth Security کاملاً قابل اتکا به SAST نیست.
بخش بزرگی از آن Configuration و Interaction میان چند Component است.
DAST و OAuth
DAST میتواند Behavior واقعی Authorization Server و Client را بررسی کند.
اما Automation باید بسیار کنترلشده باشد، زیرا Flow شامل Redirect، User Session و Token است.
بهترین روش معمولاً ترکیب:
Protocol-aware testing،
Manual Review،
Code Review،
Configuration Review
است. 
مهمترین روشهای پیادهسازی امن OAuth 2.0
یک پیادهسازی امن OAuth باید بر پایه استانداردهای جدید باشد، نه Tutorialهای قدیمی اینترنت.
مهمترین تصمیم معماری برای Clientهای User-facing معمولاً Authorization Code + PKCE است.
RFC 9700 PKCE را فراتر از Native Apps توصیه میکند و RFC 10017 نیز آن را Best Practice برای Browser-Based Applications معرفی میکند.
Redirect URI باید Exact Match داشته باشد.
Client نباید Implicit Flow را بهصورت پیشفرض انتخاب کند.
Password Grant نباید استفاده شود.
Access Token باید Scope و Audience حداقلی داشته باشد.
Refresh Token باید Rotation یا Sender Constraint داشته باشد.
Forward Flow باید با State، PKCE یا OIDC Nonce مناسب به Transaction Bind شود.
Tokenها نباید در URL یا Log قرار گیرند.
چکلیست دفاعی امنیت OAuth
| کنترل | وضعیت مطلوب |
|---|---|
| Flow اصلی | Authorization Code |
| PKCE | فعال، ترجیحاً اجباری و با S256 |
| Redirect URI | Exact Match و بدون Wildcard ناامن |
| Implicit Grant | برای طراحی جدید استفاده نشود |
| Password Grant | استفاده نشود |
| State | تصادفی، Transaction-Specific و Validateشده |
| OIDC Nonce | برای Flowهای مرتبط ایجاد و بررسی شود |
| Access Token | کوتاهعمر و حداقل Permission |
| Scope | Least Privilege |
| Audience | محدود به Resource Server موردنظر |
| Refresh Token | Rotation یا Sender Constraint |
| Token Storage | متناسب با Threat Model و خارج از Storage ناامن |
| URL | Access Token در Query قرار نگیرد |
| TLS | در تمام Endpointهای OAuth اجباری |
| Client Secret | فقط در Confidential Client |
| Mobile | Secret ثابت بهعنوان Credential واقعی تلقی نشود |
| Native Apps | External Browser + PKCE |
| Browser Apps | Authorization Code + PKCE |
| Token Validation | Signature/Issuer/Audience/Expiration/Purpose |
| Multi Provider | Issuer Validation و Mix-Up Protection |
| Sender Constraint | DPoP یا mTLS در سیستمهای حساس |
| Logs | Token و Secret Redact شوند |
| Revocation | برای Incident و Logout Policy وجود داشته باشد |
| Open Redirect | روی Client و Authorization Server وجود نداشته باشد |
| Authorization | Resource Server مستقل از Client بررسی کند |
| Monitoring | Token Replay، Scope Abuse و Refresh Failure پایش شوند |
اشتباهات رایج در امنیت OAuth
استفاده از OAuth بهعنوان Login بدون OIDC
OAuth Authorization است.
اگر Application نیاز به Identity دارد، باید OpenID Connect یا Mechanism معادل استاندارد استفاده شود.
قرار دادن Client Secret در JavaScript
Secret قابل ارسال به Browser دیگر Secret نیست.
استفاده از Implicit Flow به دلیل Tutorial قدیمی
Security Best Practice جدید Authorization Code + PKCE است.
استفاده از Password Grant
RFC 9700 صریحاً آن را ممنوع میداند.
Redirect URI با Wildcard گسترده
Redirect باید Exact Match شود.
PKCE با Verifier ثابت
Verifier باید به هر Transaction اختصاص داشته باشد.
نادیده گرفتن State یا Nonce
Transaction Binding ناقص میتواند Login CSRF یا Code Injection ایجاد کند.
Token در LocalStorage بدون Threat Model
XSS میتواند JavaScript Storage را بخواند.
Access Token بسیار طولانیعمر
اثر Token Theft افزایش پیدا میکند.
Refresh Token بدون Rotation
Public Client ممکن است قادر به تشخیص Replay نباشد.
پذیرش JWT فقط چون Decode میشود
JWT باید Cryptographically Validate شود.
عدم بررسی Audience
Token API دیگر ممکن است اشتباهاً پذیرفته شود.
Scope بیش از حد گسترده
Compromise Client Impact بسیار بیشتری خواهد داشت.
ثبت Token در Log
Log تبدیل به Credential Database ناخواسته میشود.
اعتماد به CORS بهعنوان Authorization
CORS Policy Browser است، نه Access Control Backend.
اگر آسیبپذیری OAuth پیدا شد چه کنیم؟
اول باید مشخص شود ضعف در کدام Component قرار دارد:
Client،
Authorization Server،
Resource Server،
Reverse Proxy،
یا Identity Provider Configuration.
سپس باید Credentialهای در معرض خطر شناسایی شوند.
اگر Access Token احتمالاً افشا شده:
Token Revocation بررسی شود.
اگر Refresh Token افشا شده:
Grant مربوط Revoked شود.
اگر Client Secret لو رفته:
Secret Rotate شود.
اگر Redirect URI ناامن بوده:
Redirect Registration اصلاح شود و Logهای Authorization بررسی شوند.
اگر Mix-Up یا Issuer Confusion وجود داشته:
Issuer Validation اضافه شود.
اگر مشکل PKCE بوده:
Flowهای Public Client بدون PKCE متوقف شوند.
صرف Patch Code همیشه کافی نیست؛ Credential موجود نیز ممکن است دیگر قابل اعتماد نباشد.
Incident Response برای Token Leakage
Token Leakage یک Incident Credential محسوب میشود.
تیم باید بداند:
چه Tokenهایی افشا شدهاند؟
Scope آنها چیست؟
Audience چیست؟
چه زمانی صادر شدهاند؟
Lifetime چقدر بوده؟
Refresh Token مرتبط وجود داشته؟
آیا Token استفاده غیرعادی شده؟
Resource Server Logها چه نشان میدهند؟
در صورت امکان Token باید سریع Revocation شود.
سپس Root Cause مانند XSS، Logging یا Redirect Leak برطرف شود.
امنیت OAuth و Zero Trust
OAuth خود یک Zero Trust Solution کامل نیست.
داشتن Access Token نباید همه بررسیها را حذف کند.
Resource Server باید هر Request را براساس:
Token Validity،
Scope،
Audience،
User Permission،
Resource Ownership،
Business State
بررسی کند.
OAuth فقط یکی از لایههای Authorization Architecture است.
Defense in Depth برای OAuth
معماری مناسب را میتوان چنین تصور کرد:
User
↓
Secure Browser Interaction
↓
Authorization Server
↓
Authorization Code + PKCE
↓
Trusted Client
↓
Short-lived, Scoped Token
↓
Resource Server
↓
Audience + Scope + Business Authorization
در کنار آن:
TLS
Token Rotation
Sender Constraint
Monitoring
Revocation
Secure Logging
XSS Protection
لایههای دفاعی مکمل هستند.
هدف این است که شکست یک Control بهتنهایی باعث Compromise کامل نشود.
استانداردهای فعلی امنیت OAuth چه میگویند؟
RFC 6749 پایه OAuth 2.0 است، اما Security Guidance آن طی سالها بهروزرسانی شده است.
RFC 9700 در ژانویه 2025 بهعنوان Best Current Practice امنیت OAuth 2.0 منتشر شد و RFCهای قدیمیتر را از نظر توصیه امنیتی بهروزرسانی میکند. این سند PKCE را بسیار پررنگتر کرده، Resource Owner Password Credentials Grant را ممنوع دانسته، Implicit Grant را بهطور عمومی توصیه نکرده و روی Exact Redirect Matching، Token Privilege Restriction، Sender-Constrained Token و Refresh Token Protection تأکید دارد.
برای Browser-Based Applicationها نیز RFC 10017 که در 2026 منتشر شده است، Authorization Code Flow همراه با PKCE را Best Practice فعلی معرفی میکند.
بنابراین پیادهسازیای که صرفاً مطابق Tutorialهای OAuth سالهای ابتدایی دهه 2010 نوشته شده، الزاماً مطابق Security Guidance امروزی نیست.
سؤالات متداول درباره امنیت OAuth
OAuth چیست؟
OAuth 2.0 یک Authorization Framework است که به Client اجازه میدهد بدون دریافت Password اصلی User، دسترسی محدود به Resourceهای محافظتشده دریافت کند. RFC 6749 استاندارد پایه OAuth 2.0 است.
آیا OAuth برای Login است؟
OAuth در اصل برای Authorization است. برای Authentication و Identity معمولاً OpenID Connect روی OAuth 2.0 استفاده میشود.
امنترین Flow رایج OAuth چیست؟
برای بسیاری از Applicationهای User-facing مدرن، Authorization Code Flow همراه با PKCE انتخاب اصلی محسوب میشود. نوع Client و Threat Model همچنان باید در طراحی لحاظ شوند.
آیا PKCE فقط برای Mobile App است؟
خیر. PKCE ابتدا برای Public Native Client طراحی شد، اما RFC 9700 استفاده از آن را برای انواع مختلف Client توصیه میکند.
آیا OAuth Implicit Flow هنوز باید استفاده شود؟
برای طراحی جدید معمولاً خیر. RFC 9700 استفاده از Implicit Grant را به دلیل Token Leakage و Replay بهطور عمومی توصیه نمیکند و RFC 10017 برای Browser Appها Authorization Code + PKCE را پیشنهاد میدهد.
Password Grant در OAuth امن است؟
خیر. RFC 9700 میگوید Resource Owner Password Credentials Grant نباید استفاده شود.
Redirect URI چگونه باید بررسی شود؟
Authorization Server باید Redirect URI را با URI ثبتشده با Exact String Matching مقایسه کند، بهجز استثنای مشخص Loopback Port در Native Appها.
State در OAuth چیست؟
State یک مقدار Transaction-Specific است که میتواند برای Bind کردن Authorization Request و Response و مقابله با CSRF استفاده شود. مقدار آن باید قابل حدس نباشد و هنگام Callback Validate شود.
تفاوت State و PKCE چیست؟
State عمدتاً Transaction و Browser Session را Bind میکند. PKCE Authorization Code را به Client Instance و Transaction مربوط متصل میکند و در برابر Code Interception و Code Injection محافظت مهمی ایجاد میکند. این دو مفهوم یکسان نیستند.
Access Token چیست؟
Credentialای است که Client برای دسترسی به Resource Server استفاده میکند. Permission، Lifetime و Audience آن باید محدود باشند.
Refresh Token چیست؟
Credentialای است که برای دریافت Access Token جدید استفاده میشود. چون معمولاً طولانیعمر است باید بهشدت محافظت شود. 
Refresh Token Rotation چیست؟
Authorization Server پس از هر Refresh یک Refresh Token جدید صادر و قبلی را Invalid میکند. استفاده دوباره از Token قبلی میتواند نشانه Replay باشد.
DPoP چیست؟
DPoP مکانیزمی طبق RFC 9449 برای Sender-Constraining Access و Refresh Token است. Client باید مالکیت Private Key مرتبط با Token را اثبات کند، بنابراین Token سرقتشده بهتنهایی کمتر قابل Replay است.
mTLS در OAuth چیست؟
RFC 8705 Client Authentication مبتنی بر Mutual TLS و Certificate-Bound Token را تعریف میکند. این روش در محیطهای Server-to-Server و Security-Sensitive کاربرد مهمی دارد.
آیا JWT بودن Access Token به معنی امن بودن آن است؟
خیر. JWT باید Signature، Issuer، Audience، Expiration و Claimهای مرتبطش Validate شوند. JWT فقط یک Format است.
Scope چیست؟
Scope محدوده Permission Token را مشخص میکند. براساس اصل Least Privilege فقط Permissionهای موردنیاز Client باید صادر شوند.
Audience چیست؟
Audience تعیین میکند Token برای کدام Resource Server صادر شده است. API باید بررسی کند Token واقعاً برای خودش صادر شده است.
آیا Access Token را میتوان در URL قرار داد؟
نباید Access Token در URI Query Parameter قرار گیرد. RFC 9700 صراحتاً Clientها را از این روش منع میکند.
OAuth در SPA چگونه باید پیادهسازی شود؟
راهنمای فعلی RFC 10017 استفاده از Authorization Code + PKCE را برای Browser-Based Applicationها توصیه میکند. Architecture Token Storage نیز باید براساس Threat Model انتخاب شود.
OAuth در Mobile App چگونه امن میشود؟
Native App باید از External User-Agent، Authorization Code Flow و PKCE استفاده کند و نباید Client Secret مشترک داخل Application را بهعنوان Secret قابل اعتماد در نظر بگیرد.
OAuth Mix-Up Attack چیست؟
حملهای است که Client را درباره Authorization Server صادرکننده Response گمراه میکند. RFC 9207 پارامتر iss را برای مقابله با این کلاس حملات تعریف کرده است.
PAR چیست؟
Pushed Authorization Requests یا PAR طبق RFC 9126 به Client اجازه میدهد Authorization Request را ابتدا مستقیماً به Authorization Server Push کند و سپس Reference آن را از طریق Browser ارسال کند. این کار میتواند Integrity و محرمانگی برخی Authorization Parameterها را بهبود دهد.
آیا HTTPS بهتنهایی OAuth را امن میکند؟
خیر. TLS ضروری است، اما ضعفهایی مانند Redirect URI Validation، Scope بیش از حد، Token Confusion، CSRF یا Refresh Token Replay را بهتنهایی حل نمیکند.
آیا CORS یک کنترل امنیت OAuth است؟
CORS یک Browser Security Policy است. Resource Server باید Authorization را مستقل از CORS enforce کند.
بهترین روش جلوگیری از آسیبپذیری OAuth چیست؟
استفاده از Authorization Code + PKCE، Redirect URI دقیق، Tokenهای کوتاهعمر و محدود، Refresh Token Protection، Issuer و Audience Validation، TLS، Secure Token Storage و پیروی از RFC 9700 از مهمترین اصول هستند.
جمعبندی
OAuth 2.0 یکی از مهمترین استانداردهای Authorization در Web، Mobile، API و معماریهای Cloud است، اما امنیت آن به انتخاب صحیح Flow و پیادهسازی دقیق تمام Trust Boundaryها وابسته است.
هدف OAuth این است که Client برای دسترسی محدود به Resourceهای User مجبور نباشد Password اصلی او را دریافت کند.
Client بهجای Password یک Token با Scope و Lifetime مشخص دریافت میکند.
اما همین Token یک Credential واقعی است.
اگر Redirect URI ضعیف باشد، Token ممکن است به مقصد اشتباه برسد.
اگر PKCE وجود نداشته باشد، Authorization Code سرقتشده ممکن است قابل استفاده شود.
اگر State یا Transaction Binding اشتباه باشد، Login CSRF یا Code Injection میتواند رخ دهد.
اگر Scope بیش از حد گسترده باشد، Compromise Client Impact بزرگی خواهد داشت.
اگر Audience بررسی نشود، Token یک API ممکن است در API دیگری پذیرفته شود.
اگر Refresh Token بدون Rotation یا Sender Constraint در Public Client صادر شود، Replay آن میتواند Session طولانیمدت ایجاد کند.
اگر Token در URL، Log یا Browser Storage نامناسب قرار گیرد، Leakage سادهتر میشود.
Best Current Practice امروز با OAuth سالهای ابتدایی متفاوت است.
RFC 9700 که در ژانویه 2025 منتشر شده، Security Guidance اصلی OAuth 2.0 را بهروز کرده است. این استاندارد Password Grant را ممنوع میداند، استفاده عمومی از Implicit Grant را توصیه نمیکند، PKCE را برای Clientهای مختلف مهم میداند، Redirect URI Exact Matching را الزام میکند و بر Scope، Audience، Sender-Constrained Token و Refresh Token Replay Protection تأکید دارد.
برای Browser-Based Applicationها نیز RFC 10017 در سال 2026، Authorization Code + PKCE را روش فعلی توصیهشده معرفی میکند.
در Native Apps، RFC 8252 استفاده از External Browser و PKCE را توصیه میکند.
در سیستمهایی که Token Replay Risk بالایی دارند، DPoP طبق RFC 9449 یا Mutual TLS طبق RFC 8705 میتوانند Token را به Sender مشخص Bind کنند.
در معماریهای چند Provider نیز RFC 9207 با پارامتر iss امکان مقابله استاندارد با Mix-Up Attack را فراهم میکند.
بنابراین امنیت OAuth نباید به اضافه کردن یک دکمه «Login with...» یا نصب یک SDK محدود شود.
پیادهسازی امن باید از ابتدا مشخص کند:
چه Clientی داریم؟
چه Flowای مناسب است؟
چه Scopeای واقعاً لازم است؟
Token برای کدام Resource Server صادر میشود؟
Redirectها چگونه Validate میشوند؟
Transaction چگونه با PKCE، State یا Nonce Bind میشود؟
Credentialها کجا ذخیره میشوند؟
Refresh Token چگونه Rotate یا Sender-Constrain میشود؟
و اگر Token سرقت شد، چگونه Detection و Revocation انجام میشود؟
پاسخ دقیق به همین سؤالها تفاوت میان «OAuth فعال» و «OAuth امن» را مشخص میکند.