راهنمای جامع توابع امنیتی SQL Server
دسترسی سریع
این مجموعه مرجع کاربردی برای تشخیص هویت، نگاشت Principal و طراحی Audit در SQL Server است. هر پیوند به آموزش مستقل همان تابع میرسد.
مقدمهای بر مدل امنیت SQL Server
مدل امنیتی SQL Server چندلایه است. Login در سطح Instance، User در سطح Database، Roleها، Permissionها، Schemaها و Context اجرای ماژول هر کدام مسئولیت جداگانهای دارند. توابع امنیتی این مقاله برای مشاهده بخشهایی از همین مدل هستند و پاسخ یکسانی به سؤال «چه کسی در حال اجراست؟» نمیدهند.
در اتصال معمولی ممکن است نام Login و User شبیه باشد، ولی این شباهت یک الزام نیست. اعضای sysadmin در دیتابیس اغلب dbo دیده میشوند، contained user میتواند بدون Login کلاسیک کار کند و EXECUTE AS هویت مؤثر را عوض میکند. بنابراین طراحی Audit باید Login آغازکننده، Login مؤثر و User دیتابیس را جدا ثبت کند.
SID شناسه باینری هویت و principal_id شناسه عددی داخل Catalog مربوط است. توابع SUSER در سطح سرور و توابع USER در سطح دیتابیس معنا پیدا میکنند. در مهاجرت و بازیابی دیتابیس، درک SID برای جلوگیری از Orphaned User ضروری است؛ تکیه صرف بر نام یا عدد داخلی کافی نیست.
تشخیص هویت سطح دیتابیس
توابع این گروه باید با توجه به Scope و نوع شناسه انتخاب شوند. ثبت چند خروجی مکمل معمولاً تصویر مطمئنتری از Context امنیتی میسازد.
CURRENT_USER نام کاربر پایگاهداده در Context امنیتی جاری را برمیگرداند و با USER_NAME() همارز است. برخلاف ORIGINAL_LOGIN که Login اولیه اتصال را حفظ میکند، CURRENT_USER هویت مؤثر داخل دیتابیس را نشان میدهد. آموزش کامل CURRENT_USER با مثالهای عملی
SESSION_USER نام کاربر پایگاهداده برای Context امنیتی جاری نشست را با نحو استاندارد ANSI برمیگرداند. از نظر نتیجه معمولاً با CURRENT_USER و USER_NAME() همجهت است، ولی Login سطح سرور را نباید از آن استنباط کرد. آموزش کامل SESSION_USER با مثالهای عملی
USER_ID شناسه عددی Database Principal متناظر با نام User را در پایگاهداده جاری برمیگرداند. USER_ID در محدوده دیتابیس است؛ SUSER_ID شناسه Principal سطح سرور را بررسی میکند و این دو قابل جایگزینی نیستند. آموزش کامل USER_ID با مثالهای عملی
USER_NAME نام Database User متناظر با شناسه عددی را برمیگرداند و بدون آرگومان نام کاربر جاری را ارائه میکند. USER_NAME() با CURRENT_USER همارز است؛ SUSER_SNAME() نام Login سطح سرور را هدف میگیرد. آموزش کامل USER_NAME با مثالهای عملی
تشخیص Login اولیه و مؤثر
توابع این گروه باید با توجه به Scope و نوع شناسه انتخاب شوند. ثبت چند خروجی مکمل معمولاً تصویر مطمئنتری از Context امنیتی میسازد.
ORIGINAL_LOGIN نام Login اولیهای را برمیگرداند که نشست SQL Server را ایجاد کرده است، حتی اگر Context بعداً تغییر کند. SUSER_SNAME() هویت Login مؤثر جاری را نشان میدهد اما ORIGINAL_LOGIN() مبدأ نشست را نگه میدارد. آموزش کامل ORIGINAL_LOGIN با مثالهای عملی
SYSTEM_USER نام Context امنیتی جاری را بدون پرانتز برمیگرداند و برای شناسایی هویت مؤثر اتصال بهکار میرود. برای حفظ Login آغازکننده پس از جعل هویت از ORIGINAL_LOGIN() استفاده کنید؛ SYSTEM_USER هویت مؤثر جاری را هدف میگیرد. آموزش کامل SYSTEM_USER با مثالهای عملی
نگاشت شناسههای سطح سرور
توابع این گروه باید با توجه به Scope و نوع شناسه انتخاب شوند. ثبت چند خروجی مکمل معمولاً تصویر مطمئنتری از Context امنیتی میسازد.
SUSER_ID شناسه عددی Server Principal متناظر با نام Login را برمیگرداند و بدون آرگومان Context جاری را بررسی میکند. SUSER_ID با شناسه عددی server_principal_id کار میکند؛ SUSER_SID شناسه باینری و پایدارتر SID را ارائه میدهد. آموزش کامل SUSER_ID با مثالهای عملی
SUSER_NAME نام Login متناظر با شناسه عددی Server Principal را برمیگرداند و بدون آرگومان نام Context جاری را ارائه میکند. SUSER_NAME شناسه عددی میپذیرد، در حالی که SUSER_SNAME برای تبدیل SID باینری به نام طراحی شده است. آموزش کامل SUSER_NAME با مثالهای عملی
SUSER_SID SID باینری Login مشخصشده یا Context امنیتی جاری را برمیگرداند. برخلاف SUSER_ID که شناسه عددی داخلی نمونه است، SID برای نگاشت هویت میان Metadata امنیتی اهمیت بیشتری دارد. آموزش کامل SUSER_SID با مثالهای عملی
SUSER_SNAME نام Login متناظر با SID باینری را برمیگرداند و بدون آرگومان نام Context امنیتی جاری را نمایش میدهد. SUSER_SNAME ورودی باینری SID میگیرد؛ SUSER_NAME ورودی عددی server_principal_id را تبدیل میکند. آموزش کامل SUSER_SNAME با مثالهای عملی
جدول مقایسه توابع
| تابع | کاربرد اصلی | نوع خروجی یا نکته مهم | لینک آموزش کامل |
|---|
| CURRENT_USER | کنترل مجوزهای سطح دیتابیس، ثبت کاربر مؤثر و عیبیابی EXECUTE AS USER | nvarchar(128)؛ Scope: پایگاهداده | مطالعه CURRENT_USER |
| ORIGINAL_LOGIN | ممیزی غیرقابلابهام، تشخیص آغازکننده واقعی عملیات و بررسی زنجیرههای EXECUTE AS | sysname؛ Scope: سرور و نشست | مطالعه ORIGINAL_LOGIN |
| SESSION_USER | کدهای قابلانتقال ANSI، سیاستهای سطح سطر و ثبت کاربر مؤثر دیتابیس | nvarchar(128)؛ Scope: پایگاهداده | مطالعه SESSION_USER |
| SUSER_ID | اتصال نام Login به sys.server_principals، گزارش امنیتی و اعتبارسنجی Principalهای سطح سرور | int؛ Scope: سرور | مطالعه SUSER_ID |
| SUSER_NAME | خواناسازی شناسههای امنیتی در گزارشها و تبدیل server_principal_id به نام قابل فهم | nvarchar(128)؛ Scope: سرور | مطالعه SUSER_NAME |
| SUSER_SID | تطبیق Login و User، انتقال دیتابیس، تشخیص Orphaned User و ممیزی بر پایه شناسه باینری | varbinary(85)؛ Scope: سرور | مطالعه SUSER_SID |
| SUSER_SNAME | ترجمه SID به نام، تحلیل Audit، بررسی sys.server_principals و عیبیابی نگاشت هویت | nvarchar(128)؛ Scope: سرور | مطالعه SUSER_SNAME |
| SYSTEM_USER | ثبت هویت جاری در Audit، Default Constraintها و گزارش عیبیابی نشست | nvarchar(128)؛ Scope: سرور و نشست | مطالعه SYSTEM_USER |
| USER_ID | اتصال نام User به sys.database_principals، بررسی مالکیت و تولید گزارش مجوزهای دیتابیس | int؛ Scope: پایگاهداده | مطالعه USER_ID |
| USER_NAME | خواناسازی principal_id، گزارش مجوزها، نمایش مالک اشیا و تحلیل Context سطح دیتابیس | nvarchar(128)؛ Scope: پایگاهداده | مطالعه USER_NAME |
مثالهای ترکیبی و عملی
مثال 1: مقایسه سه لایه هویت
این Query یک سناریوی مستقل و قابل اجرا برای فهم مرزهای امنیتی ارائه میکند. خروجی واقعی به نوع احراز هویت، Principalهای موجود و مجوز مشاهده Metadata وابسته است.
SELECT ORIGINAL_LOGIN() AS OriginalLogin,
SUSER_SNAME() AS EffectiveLogin,
CURRENT_USER AS DatabaseUser;
| نتیجه مورد انتظار | نکته |
|---|
| نام اولیه، نام مؤثر و User دیتابیس | نامها و شناسهها را در Context همان اتصال تفسیر کنید. |
در پروژه واقعی، زمان UTC، شناسه نشست، نام برنامه و شناسه عملیات کسبوکار را نیز کنار داده امنیتی ثبت کنید.
مثال 2: نگاشت Login جاری به SID و برگشت
این Query یک سناریوی مستقل و قابل اجرا برای فهم مرزهای امنیتی ارائه میکند. خروجی واقعی به نوع احراز هویت، Principalهای موجود و مجوز مشاهده Metadata وابسته است.
DECLARE @Sid varbinary(85)=SUSER_SID();
SELECT @Sid AS LoginSid,SUSER_SNAME(@Sid) AS LoginName;
| نتیجه مورد انتظار | نکته |
|---|
| SID باینری و نام Login متناظر | نامها و شناسهها را در Context همان اتصال تفسیر کنید. |
در پروژه واقعی، زمان UTC، شناسه نشست، نام برنامه و شناسه عملیات کسبوکار را نیز کنار داده امنیتی ثبت کنید.
مثال 3: نگاشت User جاری به شناسه و برگشت
این Query یک سناریوی مستقل و قابل اجرا برای فهم مرزهای امنیتی ارائه میکند. خروجی واقعی به نوع احراز هویت، Principalهای موجود و مجوز مشاهده Metadata وابسته است.
DECLARE @Id int=USER_ID();
SELECT @Id AS UserId,USER_NAME(@Id) AS DatabaseUser;
| نتیجه مورد انتظار | نکته |
|---|
| شناسه عددی و نام User | نامها و شناسهها را در Context همان اتصال تفسیر کنید. |
در پروژه واقعی، زمان UTC، شناسه نشست، نام برنامه و شناسه عملیات کسبوکار را نیز کنار داده امنیتی ثبت کنید.
مثال 4: ثبت رخداد ممیزی نمونه
این Query یک سناریوی مستقل و قابل اجرا برای فهم مرزهای امنیتی ارائه میکند. خروجی واقعی به نوع احراز هویت، Principalهای موجود و مجوز مشاهده Metadata وابسته است.
DECLARE @Audit TABLE
(OriginalLogin sysname,EffectiveLogin sysname,DatabaseUser sysname,CapturedAt datetime2);
INSERT @Audit
SELECT ORIGINAL_LOGIN(),SUSER_SNAME(),CURRENT_USER,SYSDATETIME();
SELECT * FROM @Audit;
| نتیجه مورد انتظار | نکته |
|---|
| یک رخداد کامل ممیزی | نامها و شناسهها را در Context همان اتصال تفسیر کنید. |
در پروژه واقعی، زمان UTC، شناسه نشست، نام برنامه و شناسه عملیات کسبوکار را نیز کنار داده امنیتی ثبت کنید.
مثال 5: بررسی Permission بهجای نام
این Query یک سناریوی مستقل و قابل اجرا برای فهم مرزهای امنیتی ارائه میکند. خروجی واقعی به نوع احراز هویت، Principalهای موجود و مجوز مشاهده Metadata وابسته است.
SELECT IS_ROLEMEMBER(N'db_datareader') AS IsReader,
HAS_PERMS_BY_NAME(DB_NAME(),N'DATABASE',N'SELECT') AS HasSelect;
| نتیجه مورد انتظار | نکته |
|---|
| وضعیت Role و مجوز واقعی | نامها و شناسهها را در Context همان اتصال تفسیر کنید. |
در پروژه واقعی، زمان UTC، شناسه نشست، نام برنامه و شناسه عملیات کسبوکار را نیز کنار داده امنیتی ثبت کنید.
مثال 6: گزارش نگاشت Principalهای دیتابیس
این Query یک سناریوی مستقل و قابل اجرا برای فهم مرزهای امنیتی ارائه میکند. خروجی واقعی به نوع احراز هویت، Principalهای موجود و مجوز مشاهده Metadata وابسته است.
SELECT dp.principal_id,dp.name,dp.type_desc,dp.sid,
SUSER_SNAME(dp.sid) AS MappedLogin
FROM sys.database_principals AS dp
WHERE dp.principal_id>4
ORDER BY dp.name;
| نتیجه مورد انتظار | نکته |
|---|
| Principalهای دیتابیس و Login قابل نگاشت | نامها و شناسهها را در Context همان اتصال تفسیر کنید. |
در پروژه واقعی، زمان UTC، شناسه نشست، نام برنامه و شناسه عملیات کسبوکار را نیز کنار داده امنیتی ثبت کنید.
طراحی ممیزی و کنترل دسترسی
Audit خوب فقط نام کاربر را ذخیره نمیکند. حداقل Login اولیه، Login مؤثر، User دیتابیس، زمان UTC، SPID، نام برنامه، عملیات، شیء هدف و نتیجه موفق یا ناموفق ثبت میشود. داده ممیزی باید Append-only، محدود و دارای سیاست نگهداری مشخص باشد.
توابع هویتی ابزار مشاهدهاند، نه موتور مجوزدهی. تصمیم دسترسی با GRANT، DENY، Role، Row-Level Security، Dynamic Data Masking در جای درست، مالکیت و Module Signing پیاده میشود. مقایسه مستقیم نام admin یا dbo هم شکننده است و هم اصل حداقل دسترسی را نقض میکند.
برای Connection Pooling باید تفاوت نشست فیزیکی و درخواست منطقی را در نظر گرفت. هویت کاربر برنامه ممکن است در Token یا جدول نشست برنامه باشد، در حالی که همه درخواستها با یک Login سرویس به SQL Server میرسند. این دو هویت باید جدا و قابل پیوند ثبت شوند.
کارایی، پایش و بهترین روشها
توابع امنیتی معمولاً سبک هستند، ولی تکرار آنها روی میلیونها ردیف، تبدیل ضمنی و Predicate غیرقابل Seek هزینه ایجاد میکند. مقادیر ثابت نشست را یکبار محاسبه کنید و روی ستون ایندکسشده تابع قرار ندهید.
Actual Execution Plan، STATISTICS IO و TIME، Query Store و Extended Events برای اندازهگیری پیش و پس از تغییر مناسباند. آزمون باید با حجم داده، پارامتر و سطح همزمانی نزدیک به تولید انجام شود و فقط زمان نمایشدادهشده در SSMS معیار تصمیم نباشد.
- Login، User، SID و principal_id را یک مفهوم فرض نکنید.
- ORIGINAL_LOGIN و هویت مؤثر را جدا ثبت کنید.
- NULL و محدودیت Metadata Visibility را پوشش دهید.
- مجوز را بر پایه Role و Permission اعمال کنید.
- Audit را در برابر تغییر غیرمجاز محافظت کنید.
- رفتار Azure SQL و EXECUTE AS را جدا آزمایش کنید.
سؤالات متداول
پرسش 1: این تابع دقیقاً چه مسئلهای را حل میکند؟
هویت یا شناسه امنیتی مرتبط با Context اجرا را بهشکل استاندارد SQL Server در اختیار Query میگذارد. نتیجه برای عیبیابی، Audit و گزارش مجوزها ارزشمند است، اما بهتنهایی جایگزین کنترل Permission، Role و سیاست حداقل دسترسی نیست. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
پرسش 2: برای شروع یادگیری این تابع چه پیشنیازی لازم است؟
شناخت تفاوت Login سطح سرور، User سطح دیتابیس، SID، Context نشست و دستور EXECUTE AS ضروری است. تمرین روی یک Instance آزمایشی با چند Login و User باعث میشود تفاوت خروجیها بهصورت عملی و بدون خطر برای محیط تولید دیده شود. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
پرسش 3: آیا استفاده از این تابع در پروژههای تجاری مفید است؟
بله، بهویژه در سامانههای چندکاربره، پنلهای مدیریتی و فرایندهای ممیزی. ارزش تجاری زمانی ایجاد میشود که خروجی تابع همراه زمان، نشست، نام برنامه، عملیات و شناسه رکورد ثبت شود تا تحلیل رخداد و پاسخگویی ممکن باشد. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
پرسش 4: برای طراحی Audit سازمانی با این تابع چه روشی مناسب است؟
ابتدا نیازهای حقوقی و عملیاتی تعیین و سپس هویت اولیه و مؤثر، زمان UTC، شناسه نشست و جزئیات عملیات ثبت شود. در پروژههای حساس، بازبینی معماری امنیت، مشاوره SQL Server و آزمون نفوذ مجوزها پیش از انتشار توصیه میشود. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
پرسش 5: این تابع با توابع مشابه چه تفاوتی دارد؟
مرز اصلی در Scope و نوع شناسه است: برخی توابع Login سطح سرور، برخی User سطح دیتابیس و برخی SID یا شناسه عددی را برمیگردانند. انتخاب درست باید بر پایه سؤال دقیق کسبوکار باشد، نه شباهت ظاهری نام توابع. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
پرسش 6: آیا میتوان از نتیجه تابع در Trigger یا Stored Procedure استفاده کرد؟
از نظر فنی در بسیاری از سناریوها بله، اما باید رفتار مالکیت، EXECUTE AS، ماژول امضاشده و Connection Pooling آزمایش شود. پیش از پیادهسازی تراکنشی، نوع و طول ستون Audit و سیاست خطا نیز مشخص شود تا عملیات اصلی مختل نشود. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
پرسش 7: رایجترین خطا هنگام استفاده از این تابع چیست؟
رایجترین خطا یکی دانستن Login و Database User و سپس اعطای دسترسی بر پایه مقایسه یک رشته است. خطای دیگر نادیده گرفتن NULL، Metadata Visibility و Context جانشین است. ثبت خروجی توابع مکمل به تشخیص علت کمک میکند. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
پرسش 8: آیا فراخوانی این تابع باعث افت کارایی میشود؟
یک فراخوانی معمولاً سبک است، اما تکرار غیرضروری در میلیونها ردیف یا قرار دادن تبدیل روی ستون ایندکسشده میتواند هزینه بسازد. مقدار ثابت نشست را یکبار در متغیر بگیرید و Predicate را SARGable نگه دارید. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
پرسش 9: بهترین روش امنیتی برای استفاده از نتیجه چیست؟
نتیجه را برای مشاهده و ممیزی بهکار ببرید و تصمیم مجوز را به Role، GRANT، DENY، Row-Level Security یا ماژول امضاشده بسپارید. داده ممیزی باید حداقل دسترسی، نگهداری مشخص و محافظت در برابر تغییر داشته باشد. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
پرسش 10: سازگاری تابع در نسخههای SQL Server و Azure چگونه است؟
هسته تابع در نسخههای رایج پشتیبانی میشود، اما Azure SQL Database، Managed Instance، Fabric و Synapse در Metadata سطح سرور یا EXECUTE AS تفاوت دارند. پیش از مهاجرت، مستندات نسخه هدف و تست خودکار سازگاری بررسی شود. انتخاب تابع مناسب با تعیین Scope سرور یا دیتابیس و نوع خروجی آغاز میشود.
سؤالات مصاحبه
سؤال مصاحبه 1: چرا CURRENT_USER و ORIGINAL_LOGIN ممکن است متفاوت باشند؟
اولی User مؤثر دیتابیس و دومی Login آغازکننده نشست است؛ نگاشت dbo یا EXECUTE AS اختلاف طبیعی ایجاد میکند.
سؤال مصاحبه 2: SID چه نقشی دارد؟
SID هویت Login و User را به هم مرتبط میکند و در مهاجرت برای جلوگیری از کاربر یتیم مهم است.
سؤال مصاحبه 3: چگونه Audit قابل اعتماد طراحی میکنید؟
چند لایه هویت، زمان UTC، نشست، عملیات و نتیجه را ثبت و داده را در برابر تغییر محافظت میکنم.
سؤال مصاحبه 4: نام کاربر یا Permission؛ کدام برای مجوز؟
Permission و Role معیار مجوز هستند؛ نام صرفاً داده مشاهده و ممیزی است.
سؤال مصاحبه 5: چگونه عملکرد را میسنجید؟
Plan واقعی، IO، CPU، مدت، Query Store و بار همزمان را پیش و پس از تغییر مقایسه میکنم.
جمعبندی و مسیر مطالعه
توابع امنیتی SQL Server زمانی درست استفاده میشوند که Scope، Context و نوع Principal روشن باشد. برای Audit، هویت اولیه و مؤثر را جدا ثبت کنید؛ برای مجوز از Permission و Role بهره بگیرید؛ برای مهاجرت SID را جدی بگیرید و تفاوت سرویسهای ابری را آزمایش کنید.