امنیت

مقدمه ای بر مكانیزم های امنیتی در NET Framework.

  سعید احمدلوئی
ماهنامه شبکه - تیر ۱۳۸۴ شماره 55

اشاره :

مسئله فراهم كردن امنیت سیستم‌های نرم‌افزاری، همواره یكی از مسایل مهم و پیچیده تولیدكنندگان نرم‌افزار بوده و هست و سیستم‌های بسیار متنوعی برای این منظور ایجاد شده‌اند كه در این مقاله یكی از جدیدترین آن‌ها یعنی ساختار امنیتی را كه مایكروسافت در قالب NET. ارایه كرده است به صورت اجمالی بررسی می‌كنیم. شاید بتوان گفت كه با توجه به مفاهیم جدیدی كه مایكروسافت در NET. مطرح كرده است، ساختار امنیتی NET. در نوع خود بی‌نظیر است و این اولین‌بار است كه مایكروسافت چنین سیستمی را ارایه كرده است. در اینجا قصد ارزیابی قدرت امنیتی NET. را نداریم و فقط به صورت اجمالی مفاهیم و قابلیت‌های آن را توضیح خواهیم داد.




 



قبل از پرداختن به موضوع امنیت در NET. آشنایی با دو مفهوم ضروری‌است كه مختصراً هریك را تعریف می‌كنیم. 
CLR) Common language runtime): محیط زمان اجرای NET. است كه به عنوان موتوری جهت مدیریت و اجرای  كدها می‌باشد و كدهایی كه تحت آن اجرا‌ می‌شوند، اصطلاحاً managed code نامیده می‌شوند. مهم‌ترین وظیفهCLR ، كامپایل زمان اجرا (SIT) می‌باشد كه در طی آن managed code كه به زبان MSIL می‌باشد، را به كدهای اجرایی سیستم تبدیل می‌كند.

Type safe code:
این نوع كدها فقط می‌توانند به حافظه‌ای كه به ‌آن‌ها اختصاص داده شده است دسترسی پیدا كنند. به عبارت دیگر، CLR دسترسی به حافظه توسط این كدها را كنترل می‌كند و چنانچه حافظه موردنظر در اختیار این كد باشد CLR، مجوز دسترسی به حافظه را می‌دهد. فرآیندی اختیاری تحت عنوان verification process وجود دارد كه CLR  آن را هنگام لود شدن برنامه انجام می‌دهد. CLR درطی این فرآیند با استفاده از كدهای MSIL  مشخص می‌كند كه كد Type safe است یا نه. چنانچه كدی Type safe باشد CLR طی اجرای كد، دسترسی آن به تمام منابع حیاتی را كنترل خواهد كرد و در صورت لزوم اجازه دسترسی را نخواهد داد.
با معرفی این دو مفهوم، مشخص می‌شود كه كد نوشته شده در NET. باید از نوع managed code باشد تا بتواند از قابلیت‌های امنیتی موجود در NET. استفاده كند. در NET Framework. كلاس‌های زیادی جهت فراهم نمودن سرویس‌های امنیتی وجود دارد كه هر یك به طریقی سرویس خاصی را فراهم‌می‌كند. در ادامه دو مكانیزم امنیتی جدید را كه در NET Framework. وجود دارد مورد بررسی قرار می‌دهیم.


1- Code Access Security 
وقتی كه یك فایل اجرایی را اجرا می‌كنید، این فایل با دسترسی كاربری كه آن را اجرا می‌كند، اجرا خواهد شد. در وقتی كه با عنوان administrator وارد سیستم می‌شوید، چنانچه كدی را اجرا كنید، این كد به همراه قابلیت دسترسی administrator اجرا خواهد شد. با استفاده از مكانیزم Code Access Security، كد با دسترسی كه خودش تعریف می‌كند، اجرا خواهد شد. به عبارت دیگر، علاوه بر دسترسی كاربری كه كد را اجرا می‌كند، خود كد هم دارای هویت و دسترسی خواهد شد. تمام كدهایی كه به صورت managed هستند، ازCode Access Security  استفاده می‌كنند، كه این استفاده می‌تواند به صورت صریح توسط نویسنده كد عنوان شود و یا NET. به صورت پیش‌فرض، تنظیمات پیش‌فرض را برای آن اعمال ‌كند. به‌طور كلی كارهایی كه با Code Access Security می‌توان انجام‌داد عبارتند از: 
1- تعریف مجوزهای دسترسی (Permission)  
2- تعریف و تنظیم سیاست‌های امنیتی (Security Policy)  
3- درخواست مجوز (Permission) توسط كد برای خودش جهت اجرای صحیح برنامه
4- امكان درخواست مجوز توسط كد برای فراخوانی  كد. به عبارت دیگر برنامه از اجراكننده خود درخواست می‌كند 
    حتماً مجوز خاصی داشته باشد. 
5- درخواست امضای دیجیتال توسط كد برای اجراكننده كد. به عبارت دیگر كد از اجراكننده خود می‌خواهد حتماً امضای CA خاصی را داشته باشد.

جهت استفاده از این مكانیزم امنیتی چند مورد را باید رعایت كنید:
یكم: باید managed code تولید كنید و كد نوشته‌شده توسط شما type safe باشد (فقط ++VC قادر به تولیدunmanaged code می‌باشد. لذا حالت‌های پیچیده متعددی را می‌تواند تولید كند كه فراتر از موضوع این مقاله می‌باشد. در C  هم چنانچه از كلمه كلیدی unsafe استفاده نكنید كد شما type safe خواهد بود.)
دوم: از یكی از دو روشی كه Code Access Security را وارد برنامه شما می‌كند، استفاده كنید كه در ادامه توضیح داده می‌شود.
سوم: كه از همه مهمتر می‌باشد، ضروری ‌است هنگام طراحی و تحلیل برنامه، تحلیلی امنیتی نیز روی كلاس‌های خود داشته باشید و بدین ترتیب مجوزهای مختلفی را كه یك كلاس و یا متد در شرایط مختلف لازم دارد را پیدا كنید و تدابیر لازم جهت پیاده‌سازی را بیندیشید.
همان‌طور كه اشاره شد،Code Access Security به دو شیوه می‌تواند در كدهای شما پیاده‌سازی شود كه هر یك قابلیت‌های خاصی را در اختیار شما قرار می‌دهد:


  imerative security syntax 
در این مدل از یك سری كلاس‌هایی كه سرویس‌های امنیتی را فراهم می‌كنند، اشیائی گرفته و مكانیزم
code Access را پیاده‌سازی می‌كنند. از این مدل زمانی استفاده می‌شود كه تصمیمات امنیتی باید به صورت runtime گرفته شوند و تمام مسایل و تصمیمات در هنگام طراحی برنامه روشن و واضح نیستند. جهت روشن‌تر شدن موضوع به مثال زیر توجه كنید:





public Class MyClass

Public sub New

End Sub

Public Sub MyMethod1()

'using imperative security syntax to demand FileIOPermission
Dim MyFileIOPerm As New FileIOPermission()
MyFileIOPerm.Demand()

End Sub

End Class


در اینجا با استفاده از كلاس FileIOPermission مشخص كرده‌ایم كه فراخواننده این كد باید اجازه دسترسی، خواندن و نوشتن فایل‌ها را داشته باشد. نكته قابل توجه این است كه فراخواننده فقط جهت اجرای تابع 1 My Method این دسترسی را لازم دارد و چنانچه در حین استفاده از برنامه سراغ این تابع نرود، به این دسترسی هم نیازی نخواهد داشت. كلاس‌های زیادی وجود دارند كه همانند FileIOPermission دسترسی امنیتی خاصی را تعریف می‌كنند و تقریباً تمام این كلاس‌ها غیرقابل ارث‌بری می‌باشند. شما می‌توانید با توجه به نیاز خاصی كه در یك تابع و یا كلاس خود دارید، از این كلاس‌ها استفاده كنید. در اینجا برخی از پركاربردترین این كلاس‌ها را نام می‌بریم:
   Registry Permission،Web Permission ،Environment Permission ،Printing Permission ،Security Permission 


Declarative Security Syntax 
در این شیوه با استفاده از attributeها، مكانیزم code Access security در برنامه پیاده‌سازی می‌شود. بدیهی است با توجه به این‌كه از attributeها جهت تعیین و یا درخواست سطح دسترسی استفاده می‌كنیم، مجوزهای كلاس‌ها و یا توابع باید به صورت ثابت در حین طراحی برنامه مشخص شوند. از این رو انعطاف‌پذیری مدل قبلی جهت تصمیم‌گیری در زمان اجرا را در این حالت نخواهیم داشت. در واقع چنانچه در حین طراحی برنامه وجود مجوز خاصی را جهت اجرای برنامه به صورت دائم ضروری می‌دانید، استفاده از این روش مناسب می‌باشد و با استفاده از آن می‌توانید در هنگام لودشدن برنامه، مجوزهای خاصی را درخواست كنید و در صورتی كه مجوز موردنظر داده نشود، از لود شدن برنامه جلوگیری كنید. به عنوان مثال به كد زیر توجه كنید:





public Class MyClass

Public sub New
'Constructor is protected by the security call

End Sub

Public Sub MyMethod1()
'Method is protected by the security call

End Sub

End Class



همان‌طور كه ملاحظه می‌كنید در سطح كلاس My Class یك attribute قرار گرفته كه مشخص می‌كند استفاده‌كننده این كلاس (فراخواننده برنامه) باید دارای مجوز FileIOPermission باشد. توجه كنید كه attribute می‌تواند در سطح كلاس، یك متد خاص و یا حتی اسمبلی باشد، و ضمناً با استفاده از ساختار Security Action مشخص می‌كنیم كه مجوز باید به چه نحو در برنامه وارد شود. به این معنی كه آیا خود برنامه لازم دارد كه این مجوز به آن داده شود یا این‌كه فراخواننده باید این مجوز را داشته باشد، كه در مثال، مقدار Demand مشخص كننده این است كه فراخواننده برنامه باید این مجوز را داشته باشد.
غالباً در برنامه‌هایی كه در NET. پیاده‌سازی می‌شوند، نیازهای امنیتی موردتوجه قرار نمی‌گیرند. با این وجود توجه داشته باشید كه با استفاده از مكانیزم Code Access Security، قابلیت اطمینان برنامه را افزایش می‌دهید و اهداف زیر تأمین می‌شوند:‌
الف- مطلع كردن CLR از مجوزهای امنیتی‌ كه برنامه شما نیاز دارد.
 ب- بدون توجه به دسترسی‌های كاربری كه برنامه را اجرا كرده است، فقط مجوزهای موردنیاز به برنامه شما داده  خواهد شد و لذا چنانچه به هر نحوی كدهای مخرب دیگری از برنامه شما جهت نفوذ و اجرا استفاده كنند، فقط دسترسی‌های داده شده به برنامه شما را خواهند داشت و لذا میزان تخریب كم‌تر خواهد شد.
 پ- احتمال بروز خطاهای زمان اجرای مربوط به مسایل امنیتی در برنامه كاهش می‌یابد.
 ت- مدیر سیستم با استفاده از ابزاری با نام Perview.exe كه در NET. موجود است می‌تواند مجوزهای موردنیاز برنامه شما را ببیند و لذا سیاست‌های امنیتی سیستم و حتی شبكه را به نحو مطلوبی تعیین كند.


 2- Role Based Security 
این مكانیزم امنیتی بسیار شبیه به مكانیزم گروه‌ها و كاربران در اكتیودایركتوری می‌باشد. با استفاده از این مكانیزم، نقش‌هایی را كه با برنامه شما در تماس خواهند بود تعریف كرده و به هر كدام مجوزهای خاصی را می‌دهید و لذا هنگام اجرا با تعیین این‌كه چه كسی وارد برنامه می‌شود، نقش خاصی را به وی نسبت می‌دهید كه مجوزهای خاصی دارد. در واقع با استفاده از Code Access Security بدون توجه به فرد اجراكننده كد، به كد برنامه مجوزهای خاصی را می‌دهید و یا از آن می‌گیرید و به‌طور كلی با كدها و برنامه‌ها سروكار دارید و با استفاده از Role Based Security به شخص اجراكننده كد مجوز خاصی می‌دهید.
Role Based Security غالباً در برنامه‌های تحت‌وب موردنیاز است كه در آن‌ها افراد مختلفی با سیستم سروكار دارند. لذا ضروری‌ است هنگام ورود به سیستم، شناسایی شوند و نقش خاصی به فرد اختصاص یابد. بدیهی است جهت استفاده از این مكانیزم لا‌زم ‌است، هنگام طراحی برنامه نقش‌هایی را كه با برنامه شما در ارتباط خواهند بود شناسایی كرده و مجوز موردنیاز برای هر كدام را تعیین كنید.
پیاده‌سازی مكانیزم Role Based تا اندازه‌ای پیچیده‌تر از code Access است، در قدم اول باید از روشی جهت Authentication كاربر استفاده كنیم. برای این منظور روش‌های مختلفی وجود دارد كه در اینجا وارد جزییات آن‌ها نمی‌شویم و فقط به ذكر اسامی آن‌ها اكتفا می‌كنیم: 
               ،windows authentication ،iis authentication ،passport authentication،forms based authentication 
پس از authentication  قدم بعدی authorization است كه  طی آن دسترسی كاربری كه هویت آن به اثبات رسیده است، به منابع مختلف كنترل می‌شود كه آیا این كاربر اجازه دسترسی به این منابع را دارد یا نه Role Based Security . در این قسمت به‌صورت مشخص وارد برنامه می‌شود. در NET Framework. به user اصطلاحاً identity  می‌گویند و group اصطلاحاً role نامیده می‌شود. در این بین چیزی تحت عنوان Principal هم وجود دارد كه یك identigy و role مربوط به آن را نمایش می‌دهد. جهت پیاده‌سازی Role Based Security ضروری‌است به صورت دقیق‌تر با این دو شیء ‌آشنا شویم. این اشیاء عبارتند از: identity ،Principal  
 
Identity
همان‌طور كه اشاره شد، identity نشانگر یك كاربر در سیستم می‌باشد. دو كلاس Generic Identity و Windows Identity، دو نوع خاص از identity را پیاده‌سازی می‌كنند. همچنین رابطی تحت عنوان IIdentity وجود دارد كه با استفاده از آن می‌توانیم identityهای خاص را كه با فیلدهای خاصی موردنیاز برنامه ما می‌باشد، تعریف كنیم.


 Principal
این شیء، شی‌ء اساسی مكانیزم Role Based Security می‌باشد. یك شی Principal كاربر و نقش‌های مربوط به آن را در خود دارد و همانند identity دو كلاس با نام‌های windows Principal و Generic Principal و یك رابط با نام IPrincipal جهت استفاده از شی Principal درNET. وجود دارد. نكته مهمی كه باید به‌خاطر داشته باشید این است كه در هر جای برنامه كه شی Principal موردنیاز باشد، تابع Staticای با نام Current Principal در كلاس thread را فراخوانی كنید. با استفاده از Role Based Security قصد داریم عضویت یك كاربر در یك نقش خاص را كنترل كنیم و یا با توجه به مشخصات خاصی كه یك كاربر دارد، تصمیم خاصی را بگیریم. در ادامه موضوع را با مثالی تشریح می‌كنیم. (توجه داشته باشید كه Authentication انجام شده است و در مرحله Authorization می‌باشیم). برای این‌كار یك شی identity به صورت زیر درست می‌كنیم: 





Dim NIdentity As WindowsIdentity = WindowsIdentity.GetCurrent()
                                                                          
                                                                             
تابع GetCurrent  اطلاعات كاربری را كه در حال حاضر وارد سیستم شده است در شی NIdentity پر می‌كند. حال در این مرحله با استفاده از همین شی و propertyهایی كه دارد، تصمیمات امنیتی خاصی را می‌توانیم بگیریم، ولی چنانچه بررسی عضویت در نقش‌ها مورد نیاز باشد، شی Principal به صورت زیر درست می‌كنیم: 
                                                                             (Dim NPrincipal As New WindowsPrincipal (NIdentity
همان‌طور كه ملاحظه می‌كنید، برای ایجاد شی Principal شی‌ء identity مربوط به آن را به سازنده windows principal می‌دهیم.  پس از ساختن دو شیء اشاره شده برای اعمال تصمیمات امنیتی در برنامه، چهار مدل یا روش وجود دارد كه با توجه به نیاز خود می‌توانیم از یك و یا تركیبی از آن‌ها استفاده كنیم. این روش‌ را می‌توانید در كادر ضمیمه ببینید.
طراحی ساختار امنیتی یك برنامه، نیازمند آشنایی دقیق با امكاناتی است كه NET Framwork. در اختیار شما قرار می‌دهد. در اینجا فقط مختصری به دو مكانیزم جدید امنیتی كه در NET. قرار داده شده، اشاره شد. لذا بدیهی است جهت طراحی ساختار امنیتی به نحو مطلوب، آشنایی با سایر امكانات امنیتی NET. ضروری‌است.








روش های اعمال تصمیمات امنیتی در برنامه


1- Configurative Security Check 
در این مدل از فایل‌های config. جهت اعمال تصمیمات امنیتی استفاده می‌كنیم. به عنوان مثال فرض كنید در سیستم وب‌ شما پوشه خاصی وجود دارد كه فقط كاربرانی كه عضو نقش Administrator و یا Developer هستند می‌توانند فایل‌های (فرم‌های) درون آن را ببینند. برای این‌كار كافی است فایلی تحت عنوان Web.config در آن پوشه درست كنید و كد زیر را در آن بنویسید:





<location path="SampelDirectory">
<system.web>
<authorization>

<allow roles="Administrators,Developers"/>
<deny users="*"/>

</authorization>
</system.web>
</location>


2- Programmatic Security Checks 
در این مدل به صورت برنامه‌نویسی تصمیمات امنیتی لازم را می‌گیریم. به عنوان مثال چنانچه كاربری كه كد را اجرا می‌كند عضو نقش Manager  باشد، و نام وی Jack  باشد این خط كد اجرا خواهد شد. درغیراین‌صورت یك exception امنیتی در برنامه ایجاد می‌شود.

3- Declarative Security Checks
 
این مدل شبیه مدل Declarative در Code Access Security می‌باشد كه قبلاً توضیح داده شد. تنها تفاوت موجود این است كه این‌بار تصمیم امنیتی براساس نقش‌ها گرفته می‌شود. به عنوان مثال تكه كد زیر قبل از تعریف یك تابع مشخص می‌كند كه فراخواننده این تابع  باید دارای نقش Manager و نام Jack باشد. 






 

جهت بررسی این كه فقط كاربران عضو گروه Public  به كد خاصی دسترسی پیدا كنند، كدی به صورت زیر می‌نویسیم:






if( Thread.CurrentPrincipal. IsInRole( "Public" ) )
'Allow access
else
'Deny access


3 Imperative Security Checks  این مدل شبیه‌ مدل قبلی است. فقط تفاوت اندكی در نحوه تصمیم‌گیری دارد. جهت روشن شدن مطلب به مثال زیر توجه كنید:





Dim UsrName As String = "Jack"

Dim UsrRole As String = "Manager"

Dim UsrPrincipalPermission As New PrincipalPermission
(UsrName,UsrRole)



در اینجا یك شیPrincipal Permission  با نام Usr Principal Permission تعریف شده است. در ادامه هرجایی از برنامه كه در محدوده این شیء قرار دارد، به صورت زیر می‌توانیم درخواست كنیم كه فراخواننده كد این Permission  را داشته باشد:





User Principal Permission. Demand()  

 


منابع: 
1-  MSDN 
2-  NET Framework Security By: Surbhi Malhotra. 


​​