کاربر با «ورود یکپارچه» وارد میشود، صفحه نام درست را نشان میدهد و API هم ۲۰۰ برمیگرداند؛ آیا OAuth امن است؟ نه لزوماً. شاید API یک ID Token را بهجای Access Token پذیرفته، شاید توکنِ صادرشده برای سرویس گزارش روی سرویس پرداخت هم کار کند، یا شاید دو درخواست همزمان Refresh بتوانند یک خانوادهٔ توکن سرقتشده را زنده نگه دارند. در این حوزه، Happy Path سبز فقط ثابت میکند مسیر کار میکند؛ امنیت را آزمونهای Binding، Replay و Authorization نشان میدهند.
این راهنما یک روش عملی و مجاز برای تست امنیت OAuth ۲.۰ و OpenID Connect ارائه میکند: ابتدا قرارداد پیادهسازی را ثبت میکنیم، سپس یک Golden Trace سالم میسازیم، هر Binding را جداگانه میشکنیم و با Oracle مستقل بررسی میکنیم کدام جزء باید درخواست را رد کند. مرجع اصلی، RFC ۹۷۰۰؛ بهترین رویهٔ امنیتی جاری OAuth ۲.۰ است که در ژانویهٔ ۲۰۲۵ منتشر شد.
پاسخ کوتاه: یک پیادهسازی قابلدفاع باید Code را به Client، Redirect URI و تراکنش متصل کند؛ Access Token را به Issuer، Audience، Scope/Action و در سناریوهای حساس به Sender؛ ID Token را به Client و رویداد ورود؛ و Refresh Token را به Client، Grant و سازوکار تشخیص Replay. تستر باید هم Authorization Server، هم Client/Relying Party و هم Resource Server را ببیند.
OAuth ۲.۰، OIDC و JWT چه تفاوتی دارند؟
OAuth ۲.۰ در RFC ۶۷۴۹ چارچوبی برای تفویض دسترسی به منابع محافظتشده است؛ پاسخ سؤال «این Client با این Grant اجازهٔ چه کاری روی کدام Resource را دارد؟». OpenID Connect یا OIDC لایهٔ هویت روی OAuth است و پاسخ میدهد «کاربر نزد این Issuer چگونه و چه زمانی احراز هویت شده و Subject پایدار او چیست؟». JWT فقط یک قالب Token است؛ هر JWT لزوماً ID Token یا Access Token نیست و هر Access Token هم لزوماً JWT نیست.
| Artifact/Protocol | مصرفکنندهٔ اصلی | کار درست | خطای خطرناک |
|---|---|---|---|
| Authorization Code | Token Endpoint | مجوز کوتاهعمر و یکبارمصرف برای Exchange | استفاده بهعنوان Session یا Bearer credential |
| Access Token | Resource Server/API | اعمال دسترسی محدود برای Audience و Action مشخص | استفاده توسط Client برای اثبات هویت کاربر |
| ID Token | OIDC Client/RP | بیان رویداد احراز هویت و Subject برای همان Client | پذیرش توسط API بهجای Access Token |
| Refresh Token | Token Endpoint | گرفتن Access Token تازه در محدودهٔ Grant | ارسال به API یا ذخیره مثل دادهٔ عادی |
| JWT | وابسته به Profile | ظرف Claims با قواعد اعتبارسنجی مشخص | اعتماد به Payload صرفاً چون قابل Decode است |
برای مبانی Request، Response، Status و Assertion به راهنمای تست API رجوع کنید. این مقاله عمداً روی امنیت جریان مجوزدهی و هویت تمرکز دارد، نه آموزش عمومی API یا تست نفوذ کامل.
بازیگران و مرز اعتماد را قبل از تست رسم کنید
- Resource Owner: کاربر یا موجودیتی که دسترسی از جانب او اعطا میشود.
- Client: برنامهای که دسترسی میخواهد؛ Public Client نمیتواند یک Secret را محرمانه نگه دارد، Confidential Client در محیط کنترلشده Credential دارد.
- Authorization Server (AS): کاربر/Client را طبق Profile میشناسد، Grant را پردازش و Token صادر میکند.
- Resource Server (RS): API که Token را اعتبارسنجی و Authorization کسبوکاری را اعمال میکند.
- OpenID Provider (OP): در OIDC، Issuer هویتی که ID Token و معمولاً UserInfo ارائه میکند.
- Relying Party (RP): Clientی که نتیجهٔ احراز هویت OIDC را مصرف میکند.
- User Agent: معمولاً مرورگر یا System Browser موبایل؛ Front Channelی که پیام در آن قابل مشاهده، Historyپذیر و تحت اثر Extension/XSS است.
یک سامانه ممکن است چند نقش را در یک محصول پیاده کند، اما در مدل تست ادغامشان نکنید. «AS Token را صادر کرد» Oracle کافی برای «RS دسترسی درست داد» نیست. همچنین Scope جایگزین بررسی Owner، Tenant، Object و وضعیت کسبوکار در Resource Server نمیشود.
خط مبنای امنیتی در سال ۲۰۲۶ چیست؟
تا ۱۱ اوت ۲۰۲۶، OAuth ۲.۱ نسخهٔ ۱۵ یک Internet-Draft است، نه RFC نهایی؛ آن را استاندارد نهایی معرفی نکنید. برای محصول موجود، RFC ۶۷۴۹ بههمراه RFC ۹۷۰۰ و Specificationهای Profileِ واقعاً استفادهشده مبنا هستند. چند نتیجهٔ مهم BCP:
- Authorization Server باید PKCE را پشتیبانی کند؛ Public Client باید از آن استفاده کند و برای Confidential Client نیز توصیه میشود.
S256روش توصیهشدهٔ Challenge است؛ وجودcode_verifierنباید Downgrade بدون Challenge را قابلقبول کند.- Redirect URI جز استثنای Port در Loopback Native App باید Exact String Match شود.
- Implicit Grant نباید انتخاب معمول باشد؛ Access Token نباید در Authorization Response/URL قرار گیرد مگر Profile خاص با کنترلهای کافی.
- Resource Owner Password Credentials یا ROPC طبق RFC ۹۷۰۰ نباید استفاده شود.
- Refresh Token در Public Client باید Rotation یا Sender Constraint داشته باشد.
- Access Token باید حداقل Scope/Action و Audience محدود داشته باشد؛ RS باید این محدودیتها را برای هر Request کنترل کند.
«بهترین رویه» را با «قانون مطلق محصول» اشتباه نگیرید. مثلاً عمر Token عدد جهانی ۵ یا ۱۵ دقیقه ندارد؛ باید از حساسیت، قابلیت Revocation، Sender Constraint، الگوی استفاده و ریسک مشتق شود و سپس همان Policy تست شود.
مجوز و ایمنی تست امنیت
این آزمونها را فقط روی سامانه، Client و حسابهایی اجرا کنید که مجوز مکتوب و محدودهٔ روشن دارند. برای طراحی Rules of Engagement، Threat Model، گزارش و Retest از راهنمای تست امنیت نرمافزار استفاده کنید.
RoE حداقلی OAuth/OIDC
- دامنهها، Issuerها، Client IDها، Redirect URIها، APIها و Environmentهای مجاز؛
- حسابها، Tenantها، Roleها و Test Clientهای اختصاصی؛
- Mutationهای مجاز، سقف Rate و ممنوعیت Password Spraying یا ایجاد بار مخرب؛
- اجازه یا ممنوعیت Callback/Redirect به دامنهٔ کنترلشدهٔ تست؛
- مسیر ابطال فوری Code/Token/Client Credential و Stop Condition؛
- قواعد ضبط HAR/Trace/Log، Redaction، Retention و دسترسی به Evidence؛
- مخاطب Escalation برای احتمال Account Takeover یا Token Leakage.
دادهٔ تست و Evidence امن
توکن واقعی را در Decoder عمومی، Ticket، Chat یا Screenshot کامل قرار ندهید. در Evidence فقط Prefix/Hash کوتاه، jti آزمایشی، زمان، Issuer، Audience و Correlation ID لازم را نگه دارید. Secret و PII باید Redact شوند. Test Account و Synthetic Profile را طبق اصول مدیریت دادهٔ تست بسازید.
OAuth Manifest؛ قرارداد را قبل از Mutation ثبت کنید
بدون Manifest، تستر نمیداند یک رفتار Failure است یا Policy. این فیلدها را برای هر Client/Environment نسخهدار کنید:
| بخش | فیلدهای لازم |
|---|---|
| Identity | Issuer دقیق، Client ID، Client Type، Owner و Environment |
| Endpoints | Authorization، Token، JWKS، UserInfo، Revocation، Introspection و Logout در صورت پشتیبانی |
| Flow | Grant/Response Type، Response Mode، PKCE، State، Nonce و Consent policy |
| Redirect | فهرست Exact URI، Scheme، Port policy و Mobile Link ownership |
| Client Auth | روش احراز Client، Algorithm/Key، Audience و Rotation |
| Token | Opaque/JWT، Type، Issuer، Audience، Scope/Authorization details، Lifetime، Clock skew و Sender constraint |
| Keys | Allowed algorithms، JWKS URI، Cache/Refresh، Rotation overlap و Unknown-kid behavior |
| Session | Refresh rotation، Replay response، Revocation، Logout، Re-auth و Step-up policy |
| Business auth | Role×Action×Object×Owner×Tenant و منابع حساس |
| Evidence | Build/Config ID، Trace ID، Audit event، redaction و Retest oracle |
اگر تیم نمیتواند Issuer، Audience یا Consumer هر Token را نام ببرد، هنوز برای تست منفی آماده نیست؛ اول Design ambiguity را حل کنید.
Golden Trace؛ مسیر سالم را به State Machine تبدیل کنید
یک ورود موفق را با دادهٔ مصنوعی و بدون افشای Credential ثبت کنید:
- Client یک تراکنش یکتا با
state،nonceدر OIDC وcode_verifierمیسازد. - Browser به Authorization Endpoint همان Issuer میرود؛
code_challengeاز نوع S256 ارسال میشود. - AS کاربر را احراز و Consent/Policy را اعمال میکند.
- Callback فقط Code و دادههای لازم را دریافت و State/Issuer را Correlate میکند.
- Client از Back Channel، Code را با Verifier و Client Authentication لازم Exchange میکند.
- RP، ID Token را طبق Profile اعتبارسنجی میکند؛ API، Access Token را مستقل میسنجد.
- Refresh، Revocation، Logout و Re-login نیز بهعنوان Transitionهای همان Grant ثبت میشوند.
برای هر Transition بنویسید: ورودی، Binding، مصرفکننده، نتیجهٔ مورد انتظار، Audit event و حالت بعد. سپس در هر تست فقط یک مؤلفه را تغییر دهید تا علت ردشدن قابل تشخیص باشد.
ماتریس پوشش؛ چه چیزی را در کدام جزء تست کنیم؟
| سطح | خطر محوری | Oracle اصلی |
|---|---|---|
| Authorization Server | Redirect ضعیف، PKCE downgrade، Code replay، Scope escalation | رد پروتکلی + عدم صدور Credential + Audit |
| Client/RP | CSRF، Mix-Up، Code injection، ID Token substitution، Token leakage | عدم ساخت Session/Binding اشتباه |
| Resource Server | Issuer/Audience/Scope/Tenant confusion و ID Token acceptance | ۴۰۱/۴۰۳ متناسب + عدم اثر جانبی |
| User Agent/Mobile | History/Referer/Storage/Deep Link interception | عدم افشای Credential و مالکیت Callback |
| Operations | Key rotation، Clock، Cache، Revocation lag و Log leakage | Availability کنترلشده بدون Fail-open |
راهنمای آزمون ضعف Authorization Server در OWASP WSTG نمونههای Redirect، Code injection، PKCE downgrade و Refresh replay را پوشش میدهد. از آن بهعنوان فهرست ایده استفاده کنید، نه جایگزین Profile و Oracle محصول.
تست Discovery، Metadata و JWKS
RFC 8414 Metadata استاندارد Authorization Server را تعریف میکند. در OIDC نیز Discovery باید به Issuer مورداعتماد متصل باشد. تست کنید:
- مقدار
issuerبا Issuer مورد انتظار Exact Match است؛ تفاوت Scheme، Host، Port، Path یا Slash نادیده گرفته نمیشود. - Authorization/Token/JWKS/UserInfo endpointها از Metadata همان Issuer میآیند، HTTPS هستند و با Redirect یا DNS به مقصد ناخواسته نمیروند.
- Client قابلیتهای اعلامشده مثل
code_challenge_methods_supportedرا با رفتار واقعی تطبیق میدهد و در نبود الزام امنیتی Fail-open نمیشود. jwks_uriتنها از محل اعتمادشده خوانده میشود؛ پاسخ نامعتبر، Content-Type غلط، Key تکراری یا Algorithm ناسازگار پذیرفته نمیشود.
سناریوهای Key Rotation
Token با Key فعلی، Key قبلی در بازهٔ Overlap و kid ناشناخته بسازید. Unknown kid میتواند یک Refresh محدود و کنترلشدهٔ JWKS ایجاد کند، نه Fetch بینهایت در هر Request. حذف Key قدیمی نباید Token معتبرِ داخل بازهٔ توافقشده را ناگهانی بشکند؛ ماندن دائمی Key منقضی نیز پذیرفتنی نیست. Outage موقت JWKS باید طبق Cache policy رفتار کند و هرگز Signature verification را دور نزند.
تست Redirect URI و Open Redirect
Redirect URI یکی از حساسترین Bindingهاست. برای Web Client، Origin مشابه کافی نیست؛ Exact URI ثبتشده معیار است. ماتریس Mutation:
- تغییر
httpsبهhttp، Host، Port، Path، Query یا Fragment؛ - Subdomain مهاجم، دامنه با Prefix/Suffix مشابه، Userinfo مانند
trusted.example@evil.example؛ - Encoding یکباره/دوباره، Slash و Backslash، Unicode/IDN و Case در بخشهای حساس؛
- Duplicate
redirect_uriبا دو مقدار و اختلاف Parser بین لایهها؛ - Redirect معتبر که خودش Open Redirect دارد؛
- حذف Redirect در Token Exchange یا ارسال URI متفاوت از Authorization Request.
Oracle فقط «۳۰۲ به دامنهٔ مهاجم نشد» نیست. AS نباید Code صادر کند، Callback نامعتبر نباید Session بسازد و Audit باید Client/Reason را بدون ثبت Code کامل نشان دهد.
تفاوت state، nonce و PKCE در تست
| کنترل | به چه چیزی Bind میکند؟ | کجا بررسی میشود؟ | جایگزین چه چیزی نیست؟ |
|---|---|---|---|
state |
Authorization Response به تراکنش/Browser session | Callback در Client | اعتبارسنجی Token یا Authorization API |
nonce |
ID Token به Authentication Request | OIDC RP پس از دریافت ID Token | PKCE برای Public Client یا Audience check |
| PKCE | Authorization Code به Client instance دارای Verifier | Token Endpoint | Scope، Redirect، Issuer یا RS authorization |
RFC 7636 PKCE را تعریف میکند. برای هر کنترل، Missing/Empty/Changed/Reused/Cross-session و Constant-value را آزمایش کنید. نتیجهٔ سالم باید قبل از ساخت Session یا استفاده از Token Fail-closed باشد.
ماتریس PKCE
- Authorization Request بدون Challenge برای Clientی که PKCE لازم دارد؛
- Challenge با
plainیا Method ناشناخته وقتی Policy فقط S256 است؛ - Token Request بدون Verifier، با Verifier اشتباه، خالی یا متعلق به Code دیگر؛
- Authorization بدون Challenge اما Token Request دارای Verifier؛ این Downgrade نباید پذیرفته شود؛
- دو Exchange همزمان با یک Code/Verifier؛ حداکثر یکی ممکن است موفق شود و Code بعد از مصرف مرده باشد.
تست Authorization Code؛ کوتاهعمر، یکبارمصرف و Bound
یک Code سالم را در چهار جهت جابهجا کنید: Client دیگر، Redirect URI دیگر، Browser session/Device دیگر و Verifier دیگر. سپس همان Request را ترتیبی و همزمان Replay کنید. AS باید Code را به Client ID، Redirect URI استفادهشده و PKCE transaction متصل کند؛ برای Confidential Client نیز Client authentication بهتنهایی Code injection را حل نمیکند.
در Failure، Access/Refresh/ID Token نباید صادر شود. اگر یکی از دو Request همزمان موفق شد، پاسخ دوم باید خطا باشد و Audit یک مصرف یکتا را نشان دهد. صرف مشاهدهٔ ۴۰۰ کافی نیست؛ بررسی کنید اثر جانبی پنهان یا Token نیمهصادرشده وجود ندارد.
Grant Type و Response Typeهای منسوخ یا نامتناسب
- Authorization Code + PKCE: انتخاب پایه برای جریانهای تعاملی مدرن؛ Bindingها را تست کنید.
- Client Credentials: برای Client acting on its own behalf؛ نباید Subject یک کاربر یا دسترسی Delegated جعل کند.
- Implicit: مسیر عادی جدید نیست؛ اگر Legacy است، Exception، Threat Model و برنامهٔ مهاجرت لازم دارد.
- ROPC/Password Grant: طبق RFC ۹۷۰۰ نباید استفاده شود؛ وجود Endpoint فعال، پذیرش MFA-bypass یا ثبت Password در Client یک Finding طراحی است.
- Device/Extension Profileها: فقط بر اساس Specification همان Profile آزمون شوند؛ نام OAuth بهتنهایی رفتار را مجاز نمیکند.
همچنین Authorization Endpoint نباید Response Type یا Response Mode اعلامنشده را بپذیرد. تغییر code به token، افزودن مقدار تکراری و ناسازگاری میان Metadata و Runtime را آزمایش کنید.
تست Client Authentication در Token Endpoint
Public Client «Secret عمومی» ندارد؛ جاسازی یک رشته در SPA یا APK آن را Confidential نمیکند. Confidential Client باید با روش ثبتشده احراز شود. سناریوها:
- Missing/Wrong Client credential، Credential متعلق به Client دیگر و Method متفاوت از Registration؛
- ارسال Credential هم در Header و هم Body با مقادیر متعارض؛
- برای
private_key_jwt: Issuer/Subject/Audience اشتباه، Expired/Future assertion،jtireplay و Key بازنشسته؛ - Rotation با بازهٔ همپوشانی مشخص و ابطال Credential قدیمی؛
- خطاهایی که وجود Client یا جزئیات Secret را بیش از حد افشا میکنند؛
- Rate limit و Lockout متناسب که به DoS ساده علیه Client مشروع تبدیل نشود.
تست Access Token در Resource Server
برای هر API، Token معتبر را در یک بُعد Mutate یا Substitute کنید:
- Issuer ناشناخته یا Key متعلق به Issuer دیگر؛
- Audience سرویس دیگر، Audience گمشده یا چند Audience نامعتبر؛
- Scope/Action ناکافی، Scope ناشناخته یا Scope متعلق به Resource دیگر؛
- Expired، Not-before آینده، Clock skew خارج از Policy و Token revoked؛
- Token کاربر دیگر، Tenant دیگر، Client Credentials بهجای Delegated user و برعکس؛
- ID Token یا Refresh Token در Header
Authorization؛ - Bearer Token در Query string؛ مسیر مجاز معمول باید Header باشد تا History/Log leakage کم شود.
۴۰۱، ۴۰۳ و اثر جانبی
۴۰۱ معمولاً نبودن/نامعتبر بودن Credential و ۴۰۳ معتبر بودن هویت اما ناکافی بودن مجوز را نشان میدهد؛ قرارداد محصول را ثبت کنید. مهمتر از Code، نبود اثر جانبی است: Balance، Order، Ledger، Queue و Audit business نباید با Request ردشده تغییر کنند.
Scope جای Authorization کسبوکار را نمیگیرد
توکن دارای orders:read هنوز نباید سفارش کاربر یا Tenant دیگر را ببیند. ماتریس Subject/Client × Action × Object × Owner × Tenant × State بسازید. این همان جایی است که راهنمای OWASP Top ۱۰ و Broken Access Control به تست پروتکل متصل میشود.
تست Scope، Resource و Consent
- درخواست Scope خارج از Registration یا Policy؛ AS باید رد یا طبق قرارداد محدود کند، نه پنهانی ارتقا دهد.
- Token Response باید Scope واقعاً اعطاشده را روشن کند؛ Client نباید Requested scope را Granted فرض کند.
- کاهش Scope در Refresh نباید دوباره به Scope وسیعتر برگردد.
- Audience/Resource باید API مقصد را محدود کند؛ یک Token عمومی برای همهٔ میکروسرویسها Blast Radius را زیاد میکند.
- Consent باید Client، داده/عمل و پیامد قابلفهم را نمایش دهد؛ تغییر Client/Scope بعد از نمایش نباید ممکن باشد.
- لغو Consent باید اثر قابلتعریف روی Grant و Tokenهای وابسته داشته باشد.
در معماری چندسرویسی، مرز Token exchange، Service-to-service identity و End-user context را با استراتژی تست میکروسرویس هماهنگ کنید؛ Forwardکردن بیقاعدهٔ Bearer Token کاربر میان تمام سرویسها طراحی امنی نیست.
تست Refresh Token، Rotation و Revocation
Refresh Token را مثل یک Credential پرارزش و طولانیاثر تست کنید:
- یک Refresh معتبر را استفاده و Token جدید بگیرید.
- Refresh قبلی را دوباره، سپس همزمان از دو Client instance مجاز تست کنید.
- بررسی کنید Rotation family و Replay detection طبق Policy عمل میکند؛ صرفاً رد Token قدیمی کافی نیست اگر Token مهاجم فعال بماند.
- Scope، Resource/Audience و Client binding را بعد از Refresh با Grant اصلی مقایسه کنید.
- Logout، Password/security event، Revocation و Inactivity expiry را جداگانه اجرا کنید.
- Lag میان AS و RS را اندازه بگیرید و رفتار Tokenهای JWT/opaque را طبق معماری ثبت کنید.
Race را با دو Request تقریباً همزمان آزمایش کنید. نتیجه باید Deterministic و قابل توضیح باشد: کدام Request برنده شد، کدام Tokenها فعال ماندند و خانواده چه زمانی Revoke شد. دو ۲۰۰ مستقل با دو Refresh فعال جدید میتواند پنجرهٔ Replay بسازد.
تست OIDC و ID Token
OpenID Connect Core ۱.۰ با Errata Set ۲ قواعد اعتبارسنجی ID Token را تعریف میکند. RP باید حداقل این موارد را متناسب با Flow/Profile بررسی کند:
issدقیقاً Issuer مورد انتظار باشد و Key واقعاً به همان Issuer متصل باشد؛audشامل Client ID باشد؛ Audience اضافی وazpطبق قواعد Profile ارزیابی شوند؛- Signature و Algorithm/Key مجاز،
exp،iatو در صورت کاربردauth_time/acr؛ nonceارسالی با مقدار داخل Token برابر، یکتا و به همان تراکنش متصل باشد؛- در Flowهای لازم،
at_hashوc_hashطبق Specification بررسی شوند؛ - Session فقط بعد از تکمیل همهٔ Validationها ساخته شود؛ Decode موفق یا Signature صحیح بهتنهایی کافی نیست.
Access Token و ID Token را جابهجا کنید
ID Token باید برای Client/RP مصرف شود، نه API. Access Token نیز نباید بدون اثبات هویتی OIDC بهعنوان Login response تفسیر شود. عمداً هر کدام را در جای دیگری ارائه کنید؛ انتظار Reject و نبود Session/اثر جانبی است.
UserInfo و کلید هویت پایدار
OIDC الزام میکند sub در UserInfo دقیقاً با sub در ID Token برابر باشد. کلید حساب محلی بهتر است زوج iss + sub باشد، نه Email یا Mobile قابلتغییر. UserInfo با Subject متفاوت، Claims اضافی یا Scope ناکافی نباید به Account linking یا ارتقای Profile منجر شود.
تست JWT و JWKS؛ Decode، Verification نیست
RFC ۸۷۲۵؛ BCP امنیت JWT بر Algorithm allowlist، اعتبارسنجی Issuer/Audience و قواعد مجزای Token typeها تأکید میکند. تستهای کلیدی:
- تغییر Payload بدون Signature معتبر، Signature ناقص و Algorithm خارج از Allowlist؛
alg=noneیا جابهجایی خانوادهٔ الگوریتم وقتی Profile Token امضاشده میخواهد؛- Key درست با Issuer/Audience/Token type غلط؛ Signature valid نباید Context substitution را مجاز کند؛
kidناشناخته، تکراری، بیشازحد بلند یا دارای ورودی مخرب؛ Lookup نباید Injection یا Path access بسازد؛jku/x5uمهاجم؛ Validator نباید URL دلخواه Token را دنبال کند و SSRF ایجاد شود؛- Claims حساس در Payload خوانا، Token بزرگ، Duplicate JSON member و ناسازگاری Parserها؛
- قواعد mutually exclusive برای ID Token، Access Token، Logout Token و Client assertion.
JWT ممکن است صحیح امضا شده باشد اما برای Recipient، زمان، Action یا Token class اشتباه باشد. Finding خوب نام دقیق Validation جاافتاده را میگوید، نه فقط «JWT قابل هک است».
تست Browser، SPA و اپلیکیشن موبایل
Browser و SPA
- Access/Refresh/ID Token در URL، History، Referer، Analytics، Error page، DOM، Console و Service Worker Log ظاهر نشود.
- Token storage با Threat Model XSS و Session سازگار باشد؛ هیچ محل Browser در برابر XSS دلخواه «کاملاً امن» نیست.
- Authorization Endpoint از CORS برای فراخوانی مستقیم Client استفاده نکند؛ Token/Metadata/JWKS فقط طبق نیاز CORS داشته باشند.
- Callback، Origin/Message sender را در الگوهای
postMessageدقیق بررسی کند. - Logout محلی و OP logout، Sessionهای فعال و Back button رفتار تعریفشده داشته باشند.
Native App
RFC ۸۲۵۲؛ OAuth ۲.۰ برای Native Apps استفاده از External User-Agent و PKCE را مبنا قرار میدهد. Embedded WebView، Custom scheme قابل تصاحب، Claimed HTTPS link بدون Association و Loopback listener روی Interface نامناسب را بررسی کنید. اپ مخرب آزمایشی فقط در Lab مجاز میتواند Callback collision را نشان دهد. جزئیات Platform، Storage و Link ownership را با راهنمای OWASP MASVS/MASTG موبایل تکمیل کنید.
نشت Token در Log، Trace و ابزارها
Authorization Code، Bearer Token، Refresh Token، Client Secret و Cookie را در این نقاط جستوجو کنید: Reverse proxy، APM، Application log، Crash report، CI artifact، HAR، Screenshot، Analytics، WAF، Support ticket و Error URL. Redaction را با Tokenهای نشانهگذاریشدهٔ آزمایشی End-to-end کنترل کنید؛ صرف وجود Mask در UI اثبات نمیکند نسخهٔ خام در Backend نمانده است.
Claims هویتی را حداقل نگه دارید. National ID، موبایل، Email، Role یا اطلاعات KYC نباید صرفاً برای راحتی در ID Token قرار گیرد. برای Purpose، Minimization، Retention و درخواستهای Subject به راهنمای تست حریم خصوصی داده رجوع کنید؛ انطباق حقوقی هر محصول به حوزه و مشاور واجدصلاحیت وابسته است.
تست چند Issuer و حملهٔ Mix-Up
Clientی که با چند AS/OP کار میکند باید بداند هر Authorization Response از کدام Issuer آمده و Token را به Endpoint همان Issuer بفرستد. RFC 9207 پارامتر iss در Authorization Response را برای شناسایی Issuer تعریف میکند.
دو Issuer آزمایشی بسازید: یکی مشروع و یکی کنترلشده در Scope. Flow را با Issuer A شروع و Response/Metadata/Token endpoint مربوط به B را تزریق کنید. Client نباید Code یا Credential را به Endpoint اشتباه ارسال کند. تفاوت کوچک در Issuer، Metadata cache مشترک، Redirect URI مشترک و انتخاب IdP در Session را نیز تست کنید.
Sender-Constrained Token و DPoP
Bearer Token هرکس آن را در اختیار داشته باشد قابل ارائه است. برای سناریوهای حساس، mTLS یا DPoP میتواند Token را به Sender متصل کند. RFC 9449 DPoP را تعریف میکند؛ DPoP بهتنهایی Authentication یا Authorization نیست.
- Proof باید Signature معتبر و
typ/algمجاز داشته باشد؛ Key خصوصی در JWK ظاهر نشود. htmوhtuبا Request واقعی،iatبا Window وjtiبا Replay cache منطبق باشند.- برای Resource Request،
athباید Access Token ارائهشده را Bind کند. - Proof یک Endpoint، Method، Token یا Key دیگر را Replay کنید؛ باید رد شود.
- DPoP nonce challenge و Retry نباید Loop بینهایت یا Fail-open بسازد.
- Token از نوع DPoP نباید بدون Proof بهشکل Bearer پذیرفته شود.
زمان، همزمانی و Failureهای عملیاتی
- Clock:
exp/nbf/iatNumericDate بر UTC است؛ مرز قبل/دقیقاً/بعد و Skew policy را تست کنید. - Concurrency: Code و Refresh Token را همزمان مصرف کنید؛ نتیجه و Token family باید سازگار باشد.
- JWKS outage: Cache معتبر میتواند Availability دهد، اما Unknown key نباید Validation را حذف کند.
- AS timeout after commit: Client نباید بیقاعده Token Request را تکرار و چند Grant/Session متناقض بسازد.
- RS cache: Revocation/Policy change lag باید اندازهگیری و با Risk پذیرفته شده باشد.
- Partial logout: خروج از Client، OP و API session سه رویداد متفاوتاند؛ رفتار هرکدام را مشخص کنید.
مثال ایرانی؛ SSO بازارگاه آفتاب
این سناریو کاملاً ساختگی است. بازارگاه آفتاب یک Web Client، اپ Android/iOS، Authorization Server مرکزی و APIهای Profile، Order و Settlement دارد. کاربران Customer، Vendor و Support هستند و هر Vendor یک Tenant مستقل دارد.
Manifest نمونه
- Issuer:
https://id.aftab.example؛ Subject محلی با زوجiss+subنگاشت میشود. - Web و Mobile از Authorization Code + PKCE S256 استفاده میکنند؛ ROPC و Implicit غیرفعالاند.
- Audienceهای Profile، Order و Settlement جدا هستند؛ Scope عمومی جای Tenant authorization را نمیگیرد.
- موبایل ورودی ۰۹۱۲،
+98912و رقم فارسی/عربی را در Enrollment نرمال میکند، اما موبایل Subject اصلی نیست. - Token time بر UTC است؛ نمایش تهران و تاریخ محلی نباید Validation را تغییر دهد.
- National ID/KYC در ID Token قرار نمیگیرد؛ Claims حداقلی و دادهٔ تست Synthetic است.
ماتریس آزمون پرریسک
| Mutation | Oracle | Evidence |
|---|---|---|
| Code اپ موبایل با Verifier وب | Token Endpoint رد کند؛ Token صادر نشود | Sanitized trace + Audit reason |
| ID Token وب به Settlement API | ۴۰۱؛ هیچ Settlement ساخته نشود | API/DB/Audit correlation |
| Access Token Order روی Profile API | Audience mismatch | RS validation event |
| Vendor A با Token معتبر، Order مربوط به Vendor B | ۴۰۳ یا قرارداد معادل؛ عدم افشای Object | Before/after data + audit |
| Refresh قدیمی پس از Rotation از Device دوم | Replay policy و Family revoke طبق قرارداد | دو Request همزمان + token status |
UserInfo با sub متفاوت |
RP Claims را استفاده نکند و Account link نسازد | Session store + identity audit |
| Issuer با Slash/Host مشابه | Exact issuer mismatch | Metadata source + RP error |
| Token در Error URL/Analytics | هیچ Credential خامی ثبت نشود | Log search با marker آزمایشی |
exp روی مرز UTC هنگام تغییر روز تهران |
نتیجه فقط طبق NumericDate/Skew باشد | Clock manifest + response |
| Support scope روی Settlement approve | Business authorization رد کند | Scope + Role/Action policy |
در این مثال، مبلغ ریال/تومان Claim هویتی نیست و Callback درگاه پرداخت نیز به Front-channel login اعتماد نمیکند. Identity، Authorization و صحت تراکنش مالی Oracleهای جدا دارند.
ابزار و اتوماسیون تست OAuth/OIDC
Proxy رهگیر برای دیدن Redirect و Cookie، Browser DevTools برای Storage/History، API client برای Token/RS، و Log/Trace برای Oracle عملیاتی مفیدند. ابزار نباید Token واقعی را به Cloud ناشناخته بفرستد. اسکنر نیز Binding کسبوکاری، Tenant یا Race را بهتنهایی اثبات نمیکند.
Postman کجا مفید است؟
Postman برای Golden Request، Environment جدا، Mutation پارامتر و Assertion پاسخ مناسب است؛ اما Browser session، Redirect ownership، Cookie و Mix-Up را کامل مدل نمیکند. Secret را در Collection export نکنید. برای ساخت تستهای نسخهدار و اجرای CLI از راهنمای تست API با Postman استفاده کنید.
پورتفولیوی اتوماسیون
- Unit/Component: Token validator با Issuer/Audience/Algorithm/Time/Type matrix؛
- Protocol integration: AS/Client/RS واقعی در Environment ایزوله، Code/PKCE/Refresh races؛
- Browser/Mobile: Redirect، Storage، System Browser و Link ownership؛
- Config checks: Metadata، Redirect allowlist، Grantها، Client auth و Key policy؛
- Operational probes: JWKS rotation، Revocation lag، Audit completeness و Redaction؛
- Manual review: Consent، Threat Model، Account linking و Business authorization.
قالب Test Case و Finding قابلدفاع
OAuth Negative Test Card
- Risk/Decision و مؤلفهٔ مسئول: AS، Client/RP یا RS؛
- Manifest/Build/Config/Issuer/Client ID بدون Secret؛
- Precondition و Test account/Tenant؛
- Golden request و دقیقاً یک Mutation؛
- Expected rejection، HTTP/protocol error و نبود اثر جانبی؛
- Audit/Trace/DB/Session oracle؛
- Evidence redaction و Token fingerprint؛
- Cleanup/Revocation و Retest result.
Finding خوب چه میگوید؟
بهجای «OAuth ناامن است» بنویسید: «Resource Server سفارش، Access Token با Issuer معتبر اما Audience سرویس گزارش را پذیرفت؛ Vendor A توانست Order متعلق به همان Tenant را بخواند. Token آزمایشی Revoke و داده پاک شد.» سپس Preconditions، تکرارپذیری، Impact، کنترل جاافتاده، Evidence حداقلی و پیشنهاد قابلآزمون را اضافه کنید. Severity را از قابلیت، داده، نقش، Tenant، نیاز به Interaction و کنترلهای جبرانی استنتاج کنید.
معیارهای سالم و ضدبازی
- پوشش Bindingها بر حسب Flow/Client/RS، نه تعداد Request؛
- درصد APIهایی که Issuer+Audience+Token type+Action را مستقل Validate میکنند؛
- نرخ Reject درست برای Cross-client/Cross-audience/Cross-tenant matrix؛
- زمان کشف و ابطال Refresh replay و دامنهٔ Token family affected؛
- JWKS rotation success و Unknown-kid request amplification؛
- Revocation/Policy propagation lag با Percentile و Context؛
- تعداد Credential markerهای یافتشده در Log/Artifact، با هدف صفر؛
- Coverage Account-linking و
iss+subinvariant؛ - Findingهای Retestشده و Regression test متصل به Root cause.
تعداد Bug، تعداد Token mutation یا درصد ۴۰۱ معیار کیفیت نیست؛ تیم میتواند با Duplicate test یا Reject اشتباه عدد را زیبا کند. Metric باید به Risk و Oracle وصل باشد.
اشتباهات رایج در تست OAuth و OIDC
- فقط Decodeکردن JWT: Signature، Issuer، Audience، Type، Time و Authorization مستقل جا میماند.
- یکیگرفتن state/nonce/PKCE: هرکدام Binding و Consumer متفاوت دارد.
- تست فقط Authorization Server: ضعف Client یا RS دیده نمیشود.
- اعتماد به Scope: Object/Owner/Tenant/State authorization حذف میشود.
- پذیرش ID Token در API: Token substitution و Audience confusion ممکن میشود.
- عدد ثابت برای Lifetime: Policy، Revocation و Risk نادیده گرفته میشود.
- استفاده از Production token در ابزار عمومی: خود تست باعث Leakage میشود.
- تست Replay ترتیبی فقط: Race واقعی Refresh/Code پنهان میماند.
- پیشنهاد OAuth ۲.۱ بهعنوان RFC نهایی: وضعیت استاندارد نادرست گزارش میشود.
- Retest فقط روی ۲۰۰/۴۰۰: Session، DB، Queue، Audit و Tokenهای باقیمانده بررسی نمیشوند.
برنامهٔ ۳۰روزهٔ بهبود تست
- هفتهٔ اول: Inventory Issuer/Client/RS/Flow، تکمیل Manifest، RoE و Golden Trace؛ ROPC/Implicit/Redirect wildcardهای فعال را علامتگذاری کنید.
- هفتهٔ دوم: Redirect، State/Nonce/PKCE، Code binding، Client authentication و OIDC validation را با Matrix منفی پوشش دهید.
- هفتهٔ سوم: Audience/Scope/Tenant/Object، Refresh race/replay، Revocation، JWT/JWKS و Leakage را تست کنید.
- هفتهٔ چهارم: Regression suite، Key rotation drill، CI lanes، Finding/Retest، Dashboard ریسک و Owner/Deadline اصلاحات را تثبیت کنید.
موارد Critical مثل Redirect به دامنهٔ مهاجم، Code injection، ID Token acceptance در API یا Cross-tenant access منتظر پایان برنامه نمیمانند؛ طبق RoE فوراً Escalate و Credentialهای آزمایشی را Revoke کنید.
چکلیست نهایی تست امنیت OAuth ۲.۰ و OIDC
- Issuer، Client type، Flow، Endpoint، Token type و Consumer نسخهدار شدهاند.
- Golden Trace و State transitionهای Code/Token/Refresh/Logout ثبت شدهاند.
- Redirect URI Exact match و Open redirect/encoding/duplicate parameter تست شده است.
- PKCE S256، Missing/Wrong verifier و Downgrade پوشش دارد.
- state، nonce و PKCE با Oracleهای جدا آزموده شدهاند.
- Code برای Client/Redirect/Transaction یکبارمصرف و Race-safe است.
- Grant/Response typeهای Legacy غیرفعال یا Exception مستند دارند.
- Client authentication و Rotation/Replay assertion تست شده است.
- RS، Issuer/Audience/Time/Type/Scope و Business authorization را مستقل بررسی میکند.
- ID Token در API و Access Token در Login پذیرفته نمیشوند.
- OIDC Claims، Nonce، UserInfo sub و Account-linking پوشش دارند.
- Refresh rotation/sender constraint، Replay family، Revocation و Logout تست شدهاند.
- JWT Algorithm/Key/Issuer/Audience/Type و JWKS rotation/SSRF کنترل شدهاند.
- Browser/Mobile storage، History، Referer و Callback ownership بررسی شدهاند.
- Token/Code/Secret در Log، Trace، CI، HAR و Analytics نشت نمیکند.
- Race، Clock skew، JWKS outage و Revocation lag Oracle دارند.
- Evidence حداقلی، Redactشده، Correlated و قابل Retest است.
پرسشهای متداول OAuth و OpenID Connect
تفاوت OAuth ۲.۰ و OpenID Connect چیست؟
OAuth ۲.۰ چارچوب تفویض دسترسی به Resource است؛ OIDC یک لایهٔ هویت روی آن برای احراز هویت و Claims کاربر است. Access Token برای API و ID Token برای Client/RP است. استفاده از OAuth خام بهعنوان Login بدون Profile هویتی، Token substitution و ابهام Subject میسازد.
آیا PKCE جای state و nonce را میگیرد؟
نه بهصورت کلی. PKCE، Code را به Client instance دارای Verifier متصل میکند و در شرایط RFC ۹۷۰۰ میتواند حفاظت CSRF فراهم کند؛ state تراکنش Callback را به Browser session Bind میکند و nonce، ID Token را به Authentication Request OIDC. Profile و Threat Model تعیین میکند کدامها لازماند؛ حذف یکی با شعار «PKCE داریم» کافی نیست.
آیا API میتواند ID Token را بهعنوان Bearer Token بپذیرد؟
خیر، مگر Specification بسیار خاص صریحاً چنین Tokenی را برای همان API تعریف کرده باشد که دیگر باید با Profile خودش ارزیابی شود. در OIDC معمول، ID Token مخاطبش Client است و API باید Access Token با Issuer، Audience، Scope/Action و Authorization مناسب را بپذیرد.
Access Token بهتر است JWT باشد یا Opaque؟
هیچ پاسخ جهانی وجود ندارد. JWT اعتبارسنجی محلی و Claims نسخهدار میدهد اما Revocation/Key/Claim exposure و Validation complexity دارد؛ Opaque Token کنترل مرکزی/Introspection میدهد اما Availability و Latency وابسته میشود. تصمیم باید از معماری و ریسک بیاید و تستها با Format واقعی سازگار شوند.
آیا تست OAuth روی Production مجاز است؟
فقط با مجوز صریح، Client/Account/Data اختصاصی، Mutationهای محدود، Stop condition و Cleanup فوری. بسیاری از سناریوهای Redirect، Replay، Race و Key failure باید ابتدا در Environment ایزوله اجرا شوند. نام «تست امنیت» مجوز دستکاری حساب یا Token واقعی کاربران نیست.
جمعبندی
تست امنیت OAuth ۲.۰ و OIDC، اجرای چند Payload مشهور روی JWT نیست. واحد واقعی تست Binding است: Code به تراکنش و Client، Access Token به Issuer/Audience/Action/Sender، ID Token به Client و Authentication event، Refresh Token به Grant و Replay policy، و هر Request به Object/Owner/Tenant واقعی.
از یک Manifest و Golden Trace شروع کنید. سپس هر بار یک Binding را با دادهٔ مصنوعی بشکنید، Reject را در جزء مسئول و نبود اثر جانبی را با Oracle مستقل ثابت کنید، Evidence را Redact و Retest را به Regression وصل کنید. این روش هم Finding دقیقتری میسازد و هم به تیم میگوید مشکل در AS، Client، RP، RS یا عملیات است.

