RBAC vs ABAC مدیریت دسترسی در سیستمهای بزرگ
هرچه یک نرمافزار بزرگتر میشود، مدیریت دسترسی کاربران نیز پیچیدهتر میشود.
در یک پروژه ساده شاید کافی باشد مشخص کنیم کاربر Admin است یا User. اما در یک سیستم سازمانی، فروشگاه بزرگ، SaaS یا پلتفرم چندمستاجری، موضوع به همین سادگی نیست.
ممکن است یک کاربر مدیر باشد، اما فقط به اطلاعات یک شعبه دسترسی داشته باشد. کاربر دیگری بتواند سفارشها را مشاهده کند، اما فقط سفارشهای مربوط به واحد خودش را ببیند. حتی ممکن است دسترسی یک کاربر بر اساس ساعت، موقعیت، مالکیت داده یا وضعیت یک Resource تغییر کند.
اینجاست که مدلهای RBAC و ABAC اهمیت پیدا میکنند.
RBAC دسترسی را بر اساس نقش کاربر مدیریت میکند، در حالی که ABAC تصمیم دسترسی را بر اساس ویژگیهای کاربر، منبع، عملیات و محیط میگیرد.
RBAC چیست؟
RBAC مخفف Role-Based Access Control است.
در این مدل، دسترسی مستقیماً به کاربر داده نمیشود؛ بلکه کاربر یک یا چند Role دارد و Roleها مشخص میکنند چه Permissionهایی در اختیار کاربر قرار دارد.
برای مثال:
User → Role → Permission
فرض کنید یک سیستم فروشگاهی داشته باشیم.
Roleها میتوانند شامل موارد زیر باشند:
Admin
Manager
Seller
Support
Customer
و Permissionها:
product.readproduct.createproduct.updateorder.readorder.updateuser.manage
در این حالت میتوان تعریف کرد:
Admin
به تمام Permissionها دسترسی دارد.
Seller
به مدیریت محصولات و مشاهده سفارشها دسترسی دارد.
Support
میتواند سفارشها و تیکتها را مشاهده کند.
Customer
فقط میتواند اطلاعات و سفارشهای خودش را مشاهده کند.
این ساختار ساده، قابل فهم و نسبتاً قابل مدیریت است.
مزیت اصلی RBAC چیست؟
بزرگترین مزیت RBAC، سادگی مدل دسترسی است.
به جای اینکه برای هر کاربر Permissionهای جداگانه تعریف کنیم، Permissionها را در Role قرار میدهیم.
مثلاً:
Admin → [Create, Read, Update, Delete]
و سپس:
Sarem → Admin
در نتیجه اگر Permission جدیدی به Admin اضافه شود، کاربران دارای این Role نیز آن Permission را دریافت میکنند.
این ساختار در پروژههایی که قوانین دسترسی نسبتاً ثابت هستند، بسیار کاربردی است.
مشکل RBAC در سیستمهای بزرگ
فرض کنید یک شرکت ۵۰۰۰ کاربر دارد.
ساختار سازمانی:
شرکت
شعبه
دپارتمان
تیم
حالا فرض کنید یک Manager فقط باید سفارشهای شعبه خودش را مشاهده کند.
در RBAC ساده ممکن است وسوسه شویم Roleهای زیادی ایجاد کنیم:
TehranManager
TabrizManager
ShirazManager
IsfahanManager
اگر تعداد شعبهها، واحدها و شرایط مختلف افزایش پیدا کند، تعداد Roleها نیز میتواند زیاد شود.
به این مشکل معمولاً Role Explosion گفته میشود.
در اینجا مشخص میشود که نقش بهتنهایی همیشه برای تصمیمگیری درباره دسترسی کافی نیست.
ABAC چیست؟
ABAC مخفف Attribute-Based Access Control است.
در ABAC، تصمیم دسترسی فقط بر اساس Role گرفته نمیشود.
سیستم میتواند ویژگیهای مختلفی را بررسی کند:
ویژگیهای کاربر
ویژگیهای Resource
نوع عملیات
شرایط محیط
برای مثال:
آیا این کاربر اجازه مشاهده این سفارش را دارد؟
سیستم میتواند بررسی کند:
User
department = sales
branch = Tehran
role = manager
Resource
type = order
branch = Tehran
ownerDepartment = sales
Action
read
Environment
time = working hours
سپس Policy تصمیم میگیرد که درخواست مجاز است یا خیر.
ABAC چگونه تصمیم میگیرد؟
میتوانیم یک Policy ساده داشته باشیم:
کاربرانی که Manager هستند، میتوانند سفارشهای شعبه خودشان را مشاهده کنند.
این Policy دیگر صرفاً به Role وابسته نیست.
ممکن است منطق آن چیزی شبیه این باشد:
user.role == "Manager"
و
user.branch == resource.branch
و
action == "read"
اگر همه شرایط برقرار باشند:
Allow
در غیر این صورت:
Deny
اینجاست که ABAC انعطاف بسیار بیشتری نسبت به RBAC پیدا میکند.
تفاوت RBAC و ABAC در یک مثال واقعی
فرض کنید یک شرکت چند شعبه دارد.
کارمند علی:
Role = Manager
Branch = Tehran
کارمند رضا:
Role = Manager
Branch = Tabriz
هر دو Manager هستند.
در RBAC ساده، هر دو یک Permission مشابه دارند:
order.read
اما سؤال مهم این است:
آیا علی باید سفارشهای تبریز را هم ببیند؟
احتمالاً نه.
اینجا ABAC میتواند شرط دیگری اضافه کند:
user.branch == order.branch
در نتیجه:
علی → سفارش تهران → مجاز
علی → سفارش تبریز → غیرمجاز
رضا → سفارش تبریز → مجاز
این همان تفاوت مهم بین نقش و شرایط دسترسی است.
RBAC و ABAC چه چیزی را کنترل میکنند؟
این دو مدل را میتوان به شکل زیر مقایسه کرد:
RBAC
تمرکز اصلی:
چه نقشی داری؟
مثلاً:
Admin
Manager
Editor
Customer
ABAC
تمرکز اصلی:
چه ویژگیهایی داری و در چه شرایطی میخواهی چه عملیاتی روی چه منبعی انجام دهی؟
یعنی:
User + Resource + Action + Environment
آیا ABAC جایگزین RBAC است؟
لزوماً نه.
در بسیاری از سیستمهای بزرگ، بهترین معماری الزاماً انتخاب یکی از این دو نیست.
میتوان از RBAC برای سطح بالای دسترسی و از ABAC برای محدودیتهای دقیقتر استفاده کرد.
برای مثال:
کاربر:
Role = Manager
این Role اجازه مشاهده سفارشها را دارد.
اما Policy تعیین میکند:
user.branch == order.branch
در نتیجه:
RBAC مشخص میکند کاربر چه نوع عملیاتی میتواند انجام دهد.
و ABAC مشخص میکند این عملیات تحت چه شرایطی مجاز است.
این ترکیب میتواند مدل دسترسی قدرتمندتری ایجاد کند.
Permission و Role را با هم اشتباه نگیریم
یکی از اشتباهات رایج در طراحی Authorization این است که Role و Permission را یکی در نظر بگیریم.
Role:
ProductManager
Permission:
product.read
product.create
product.update
ممکن است یک Role چند Permission داشته باشد.
و یک Permission نیز ممکن است در چند Role استفاده شود.
در نتیجه ساختار معمول میتواند چیزی شبیه این باشد:
User → Roles → Permissions
و در مدلهای پیچیدهتر:
User + Attributes + Resource + Action → Policy Decision
Authentication با Authorization فرق دارد
قبل از ادامه، یک تفاوت مهم دیگر را هم باید مشخص کنیم.
Authentication
یعنی:
تو چه کسی هستی؟
مثلاً کاربر با موفقیت Login کرده است.
Authorization
یعنی:
چه کاری اجازه داری انجام دهی؟
ممکن است کاربر احراز هویت شده باشد، اما اجازه حذف یک محصول را نداشته باشد.
بنابراین RBAC و ABAC بیشتر در حوزه Authorization قرار میگیرند، نه Authentication.
RBAC در چه پروژههایی مناسب است؟
RBAC معمولاً انتخاب مناسبی است وقتی که:
تعداد Roleها محدود است.
قوانین دسترسی نسبتاً ثابت هستند.
ساختار سازمانی پیچیدگی زیادی ندارد.
مدیریت Permissionها ساده است.
نیاز به Policyهای بسیار پویا ندارید.
برای مثال یک پنل مدیریت فروشگاه ممکن است Roleهایی مانند:
Admin
ProductManager
OrderManager
Support
داشته باشد.
در چنین شرایطی RBAC میتواند کاملاً کافی باشد.
ABAC چه زمانی ارزش بیشتری پیدا میکند؟
ABAC زمانی اهمیت بیشتری پیدا میکند که قوانین دسترسی وابسته به Context باشند.
برای مثال:
شعبه کاربر
دپارتمان کاربر
مالک Resource
نوع Resource
وضعیت Resource
زمان درخواست
نوع عملیات
Tenant
موقعیت یا شرایط محیطی
در یک SaaS چندمستاجری، ممکن است بخواهیم کاربر فقط به اطلاعات Tenant خودش دسترسی داشته باشد.
در اینجا یک شرط مهم وجود دارد:
user.tenantId == resource.tenantId
این شرط میتواند مستقل از Role بررسی شود.
Multi-Tenant Architecture و ABAC
در سیستمهای SaaS، مفهوم Tenant بسیار مهم است.
فرض کنید یک API داریم:
GET /api/orders
کاربر از شرکت A وارد سیستم شده است.
حتی اگر Role او:
Admin
باشد، نباید بتواند سفارشهای شرکت B را مشاهده کند.
پس صرفاً این شرط کافی نیست:
user.role == Admin
باید شرط دیگری نیز وجود داشته باشد:
user.tenantId == order.tenantId
این یکی از نمونههای واضحی است که نشان میدهد Authorization فقط به Role محدود نمیشود.
آیا RBAC سادهتر و همیشه بهتر است؟
سادگی همیشه به معنی مناسب بودن برای همه پروژهها نیست.
اگر سیستم کوچک باشد، استفاده از Policyهای پیچیده ممکن است فقط باعث افزایش پیچیدگی شود.
از طرف دیگر، اگر سیستم بزرگ باشد و قوانین دسترسی زیادی داشته باشد، یک RBAC ساده ممکن است به تعداد زیادی Role و Exception تبدیل شود.
بنابراین طراحی Authorization باید از نیاز واقعی سیستم شروع شود.
نه از اینکه کدام مدل «مدرنتر» است.
اشتباه رایج: فقط بررسی Role در Backend
یکی از مشکلات امنیتی مهم این است که توسعهدهنده فقط در Frontend بررسی کند:
isAdmin === true
و بر اساس آن دکمه حذف را نمایش دهد.
اما مخفی کردن دکمه در Frontend، Authorization واقعی نیست.
کاربر میتواند مستقیماً API را صدا بزند.
بنابراین:
Frontend برای تجربه کاربری است.
Backend باید مرجع نهایی Authorization باشد.
مثلاً حتی اگر دکمه Delete در Frontend نمایش داده نشود، API باید خودش بررسی کند که آیا کاربر Permission لازم برای حذف Resource را دارد یا خیر.
RBAC و ABAC در Next.js و ASP.NET Core
در معماریهایی مانند:
Next.js → ASP.NET Core API
میتوان Authentication را از Authorization جدا کرد.
Next.js میتواند مسئول بخشی از تجربه کاربری و کنترلهای UI باشد، اما API باید Authorization را در سمت سرور enforce کند.
در ASP.NET Core نیز میتوان از Role-Based Authorization و Policy-Based Authorization استفاده کرد.
برای مثال، به جای اینکه فقط بررسی کنیم:
Admin
میتوان Policyهایی تعریف کرد که شرایط دقیقتری را بررسی کنند.
این مدل برای سیستمهایی که Permissionهای پیچیدهتری دارند، انعطاف بیشتری ایجاد میکند.
چگونه یک سیستم دسترسی قابل توسعه طراحی کنیم؟
یک معماری مناسب معمولاً بهتر است چند مفهوم را از هم جدا نگه دارد:
User
هویت کاربر.
Role
گروهی از مسئولیتها یا دسترسیها.
Permission
عملیاتی که کاربر میتواند انجام دهد.
Resource
منبعی که عملیات روی آن انجام میشود.
Policy
قواعدی که مشخص میکنند عملیات تحت چه شرایطی مجاز است.
Context
اطلاعات محیطی مورد نیاز برای تصمیمگیری.
در نتیجه به جای اینکه تمام منطق Authorization داخل Controllerها پراکنده شود، میتوان آن را ساختاریافتهتر طراحی کرد.
یک مدل ذهنی ساده
برای به خاطر سپردن تفاوت این دو مدل:
RBAC
Role → Permission
مثلاً:
Manager → order.read
ABAC
Attributes → Policy → Decision
مثلاً:
Manager + Tehran + Order.Tehran + Read → Allow
این دو مدل رقیب مطلق یکدیگر نیستند.
در بسیاری از معماریهای واقعی میتوان از هر دو در کنار یکدیگر استفاده کرد.
جمعبندی
RBAC و ABAC دو رویکرد متفاوت برای مدیریت Authorization هستند.
در RBAC، دسترسی بیشتر حول Role میچرخد.
در ABAC، تصمیم دسترسی میتواند بر اساس مجموعهای از Attributes و Context گرفته شود.
اگر سیستم سادهای دارید، RBAC میتواند مدل قابل فهم و مناسبی برای مدیریت دسترسی باشد.
اما زمانی که سیستم شما دارای شعبههای متعدد، Tenantها، مالکیت Resource، قوانین سازمانی یا شرایط پویا است، مدلهای Policy و Attribute-Based میتوانند کنترل دقیقتری ایجاد کنند.
مهمتر از انتخاب نام مدل، این است که Authorization در یک سیستم بزرگ قابل فهم، قابل تست، قابل audit و متمرکز در Backend باشد.
چون در نهایت امنیت واقعی سیستم از جایی شروع میشود که سرور قبل از اجرای یک عملیات بتواند بهدرستی پاسخ دهد:
«این کاربر، در این شرایط، روی این Resource، اجازه انجام این Action را دارد یا نه؟»
