پرش به محتویات

احراز هویت و کنترل دسترسی

ورود نسخه اول با شماره موبایل ایران و OTP ارسالی از ملی‌پیامک انجام می‌شود. SMS یک عامل محدود و در معرض SIM Swap است؛ بنابراین عملیات حساس علاوه بر Session معتبر به Authorization دقیق، Risk Check و در صورت نیاز Step-up Authentication وابسته است.

جریان ورود

sequenceDiagram participant C as Client participant A as API participant D as PostgreSQL participant W as Worker participant S as MelliPayamak C->>A: درخواست OTP A->>D: ثبت Challenge و Outbox A-->>C: Challenge ID و زمان ارسال مجدد W->>D: دریافت Job W->>S: ارسال OTP C->>A: Challenge ID و OTP A->>D: قفل و بررسی Challenge A-->>C: Access Token و Session امن

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:

  1. Token فعلی اتمیک مصرف می‌شود.
  2. Access Token و Refresh Token جدید صادر می‌شوند.
  3. Token قبلی بلافاصله باطل می‌شود.
  4. استفاده دوباره از 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 دارد.

منابع رسمی