احراز هویت و کنترل دسترسی
ورود نسخه اول با شماره موبایل ایران و OTP ارسالی از ملیپیامک انجام میشود. SMS یک عامل محدود و در معرض SIM Swap است؛ بنابراین عملیات حساس علاوه بر Session معتبر به Authorization دقیق، Risk Check و در صورت نیاز Step-up Authentication وابسته است.
جریان ورود
API ابتدا Challenge و Outbox را اتمیک ثبت میکند. Worker ارسال را انجام میدهد. Verification با قفل Row یا Update شرطی اتمیک است تا یک OTP همزمان دوبار مصرف نشود.
شماره موبایل
- فقط شمارههای ایران پذیرفته و پس از حذف فاصله و جداکننده به E.164 با پیششماره
+98تبدیل میشوند. - ورودیهای
09...،989...و+989...فقط پس از Validation دقیق به یک مقدار Canonical نگاشت میشوند. - پاسخ درخواست OTP نباید وجود یا نبود Account را افشا کند.
- شماره کامل در Log، Metric، Trace و پیام خطا ثبت نمیشود؛ نمایش فقط Masked است.
- تغییر شماره موبایل یک عملیات حساس با Reauthentication، اعلان به شماره قبلی در صورت امکان و Audit کامل است.
سیاست OTP
| کنترل | مقدار پایه |
|---|---|
| طول | 6 رقم |
| عمر | 2 دقیقه |
| فاصله ارسال مجدد | 60 ثانیه |
| تلاش Verification | حداکثر 5 تلاش تجمعی برای Challenge و بازه ضدتقلب |
| مصرف | فقط یکبار |
| Provider | ملیپیامک پشت SMSProvider Port |
- OTP با CSPRNG تولید میشود؛
math/randممنوع است. - مقدار OTP Plaintext ذخیره یا Log نمیشود. Digest با HMAC-SHA-256، Pepper سمت Server و داده زمینهای شامل Challenge ID ساخته میشود.
- Pepper در Secret Store یا Secret File خارج از Database نگهداری و Rotation آن طراحی میشود.
- مقایسه Digest در زمان ثابت انجام میشود.
- Resend کد قبلی را باطل و کد جدید ایجاد میکند، اما شمارنده شکست را Reset نمیکند.
- Success، Expiry، تعداد تلاش، درخواست جدید یا ابطال امنیتی Challenge را غیرقابل استفاده میکند.
- Rate Limit همزمان روی موبایل، IP، Device و بازه سراسری Provider اعمال میشود و پاسخ آن
Retry-Afterدارد. - Limitها در Config امنیتی نسخهدار هستند و کاهش آنها بدون Security Review مجاز نیست.
- Message ارسالشده نام Tripylon، هدف کد و هشدار عدم اشتراک را دارد و هیچ Link ناشناختهای در آن قرار نمیگیرد.
مقادیر آغازین Rate Limit که پس از مشاهده ترافیک واقعی باید بازبینی شوند:
| Scope | ارسال | Verification ناموفق |
|---|---|---|
| موبایل | حداکثر 5 بار در یک ساعت و 10 بار در 24 ساعت | حداکثر 10 بار در 30 دقیقه، مستقل از Resend |
| Device | حداکثر 10 بار در یک ساعت و 20 بار در 24 ساعت | حداکثر 20 بار در 30 دقیقه |
| IP | حداکثر 30 بار در 10 دقیقه و 200 بار در 24 ساعت | حداکثر 100 بار در 10 دقیقه |
محدودیت IP بهدلیل NAT و IP مشترک اپراتورها بهتنهایی باعث قفل دائمی Account نمیشود و همراه Signalهای موبایل و Device ارزیابی میشود. عبور از Limit کوتاهمدت Backoff افزایشی و عبور تکرارشونده Challenge ضدربات یا Block موقت ایجاد میکند.
Session و Token
| مورد | تصمیم |
|---|---|
| Access Token | JWT با امضای Ed25519 و عمر 15 دقیقه |
| Refresh Token | مقدار Opaque با حداقل 256 بیت Entropy و Rotation یکبارمصرف |
| Idle Timeout | 30 روز از آخرین Refresh موفق |
| Absolute Timeout | 180 روز از Login اولیه |
| Session | مستقل برای هر Device و قابل ابطال تکی یا همگانی |
Access Token فقط Claimهای حداقلی iss، sub، aud، exp، iat، nbf، jti و sid را دارد. Role و Permission قابل تغییر داخل Token بلندمدت Cache نمیشوند. Algorithm، Issuer و Audience به Allowlist ثابت محدود و Key با kid Rotation میشود.
Refresh Token بهصورت selector.secret یا شناسه Session بههمراه Secret تصادفی صادر میشود. Database فقط HMAC-SHA-256 Secret با Pepper مستقل، Family، Session، زمانها و metadata امنیتی را نگه میدارد. در هر Refresh:
- Token فعلی اتمیک مصرف میشود.
- Access Token و Refresh Token جدید صادر میشوند.
- Token قبلی بلافاصله باطل میشود.
- استفاده دوباره از Token قبلی کل Family را باطل، Sessionهای مرتبط را علامتگذاری و رویداد امنیتی ایجاد میکند.
Logout تکی Session همان Device و Logout All تمام Sessionهای Account را باطل میکند. عملیات حساس مانند تغییر شماره، تغییر دسترسی مدیریتی و اقدام مالی مهم باید فعال بودن Session را آنلاین بررسی و در صورت Risk بالا Reauthentication بخواهد.
نگهداری Token در Client
- Web: Refresh Token فقط در Cookie با
HttpOnly،Secure،SameSite=Strictو Path محدود به/api/v1/authقرار میگیرد؛ ذخیره Token درlocalStorageیاsessionStorageممنوع است. اگر معماری دامنهها در آیندهSameSite=Noneرا اجبار کرد، تغییر به Security Review و کنترل CSRF صریح نیاز دارد. - درخواستهای مبتنی بر Cookie در برابر CSRF با SameSite، بررسی Origin و Token ضد CSRF برای حالتهای لازم محافظت میشوند.
- Mobile: Refresh Token فقط در iOS Keychain یا Android Keystore نگهداری میشود.
- Access Token در حافظه کوتاهعمر نگهداری میشود و در URL، Log، Crash Report یا Analytics قرار نمیگیرد.
- پاسخهای Auth دارای
Cache-Control: no-storeهستند و Token از Query String عبور نمیکند.
مدل مجوز
مدل دسترسی از استاندارد نقشها و دسترسیها پیروی میکند:
- Account سراسری است، اما Role Assignment از Membership و Scope ساختمان یا واحد به دست میآید.
- Permission مستقیم به User داده نمیشود؛ Permission از Role و Policy نسخهدار محاسبه میشود.
- نتیجه پیشفرض Deny است و Permission در هر درخواست سمت Server بررسی میشود.
- داشتن شناسه Resource مجوز دسترسی ایجاد نمیکند؛ Resource ابتدا در Tenant فعال Resolve میشود.
- Policy میتواند Role-based، Attribute-based و Relationship-based باشد؛ مانند مالکیت Unit، Assignment Ticket یا Scope مالی.
- UI فقط قابلیت را پنهان میکند و منبع امنیت نیست.
- تغییر Role، Grant، Revoke، Login، Refresh reuse، Support Access و عملیات حساس Audit میشوند.
Permission با قالب پایدار <feature>.<resource>.<action> نامگذاری میشود؛ مانند tickets.ticket.assign یا finance.invoice.approve. Wildcard برای Roleهای عادی ممنوع و برای Platform Admin نیز باید محدود، ثبت و قابل بازبینی باشد.
دسترسی پشتیبانی و ادمین
- Support Access موقت، Time-bound، دارای دلیل، Scope و تایید مناسب است.
- Impersonation پنهان ممنوع است؛ Actor واقعی و Account هدف هر دو در Audit ثبت میشوند.
- دسترسی Break-glass با Credential جدا، MFA قویتر، Alert فوری و بازبینی پس از استفاده اجرا میشود.
- Query مستقیم Production برای پشتیبانی مسیر عادی نیست؛ ابزار پشتیبانی باید همان Policyها را اعمال کند.
تهدید و پاسخ
| تهدید | کنترل اصلی |
|---|---|
| Brute force OTP | Rate Limit چندبعدی، 5 تلاش، TTL کوتاه و CSPRNG |
| Enumeration | پاسخ و زمانبندی نزدیک به هم برای Account موجود و ناموجود |
| SIM Swap | Risk Check، اعلان امنیتی و Step-up برای عملیات حساس |
| سرقت Refresh Token | Digest-only، Rotation، Reuse Detection و ابطال Family |
| XSS | عدم ذخیره Token در Web Storage و Cookie امن |
| CSRF | SameSite، Origin Check و CSRF Token در مسیر Cookie |
| IDOR و Cross-tenant | Scope ساختمان، Policy هر درخواست و RLS |
| افشای Secret | Redaction، Secret خارج Git و Rotation |
معیار پذیرش
- آزمون Race ثابت کند یک OTP یا Refresh Token فقط یکبار مصرف میشود.
- هیچ OTP، Access Token یا Refresh Token Plaintext در Database و Log وجود ندارد.
- سناریوهای Expiry، Resend، پنج خطا، Reuse، Logout تکی و Logout All آزمون Integration دارند.
- تمام Endpointها جز Allowlist عمومی با Middleware احراز هویت و Authorization مرکزی محافظت میشوند.
- هر Permission حساس آزمون Allow و Deny و آزمون Cross-tenant دارد.