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

مسئله فراهم كردن امنيت سيستم‌هاي نرم‌افزاري، همواره يكي از مسايل مهم و پيچيده توليدكنندگان نرم‌افزار بوده و هست.

 

سيستم‌هاي بسيار متنوعي براي اين منظور ايجاد شده‌اند كه در اين مقاله يكي از جديدترين آن‌ها يعني ساختار امنيتي را كه مايكروسافت در قالب 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 گرفته شوند و تمام مسايل و تصميمات در هنگام طراحي برنامه روشن و واضح نيستند. جهت روشن‌تر شدن موضوع به مثال زير توجه كنيد:


</FONT>
publicClassMyClassPublicsubNewEndSubPublicSub MyMethod1()'using imperative security syntax to demand FileIOPermissionDim MyFileIOPermAsNew FileIOPermission() MyFileIOPerm.Demand()EndSubEndClass

در اينجا با استفاده از كلاس FileIOPermission مشخص كرده‌ايم كه فراخواننده اين كد بايد اجازه دسترسي، خواندن و نوشتن فايل‌ها را داشته باشد. نكته قابل توجه اين است كه فراخواننده فقط جهت اجراي تابع 1 My Method اين دسترسي را لازم دارد و چنانچه در حين استفاده از برنامه سراغ اين تابع نرود، به اين دسترسي هم نيازي نخواهد داشت. كلاس‌هاي زيادي وجود دارند كه همانند FileIOPermission دسترسي امنيتي خاصي را تعريف مي‌كنند و تقريباً تمام اين كلاس‌ها غيرقابل ارث‌بري مي‌باشند. شما مي‌توانيد با توجه به نياز خاصي كه در يك تابع و يا كلاس خود داريد، از اين كلاس‌ها استفاده كنيد. در اينجا برخي از پركاربردترين اين كلاس‌ها را نام مي‌بريم:
Registry Permission،Web Permission ،Environment Permission ،Printing Permission ،Security Permission
Declarative Security Syntax
در اين شيوه با استفاده از attributeها، مكانيزم code Access security در برنامه پياده‌سازي مي‌شود. بديهي است با توجه به اين‌كه از attributeها جهت تعيين و يا درخواست سطح دسترسي استفاده مي‌كنيم، مجوزهاي كلاس‌ها و يا توابع بايد به صورت ثابت در حين طراحي برنامه مشخص شوند. از اين رو انعطاف‌پذيري مدل قبلي جهت تصميم‌گيري در زمان اجرا را در اين حالت نخواهيم داشت. در واقع چنانچه در حين طراحي برنامه وجود مجوز خاصي را جهت اجراي برنامه به صورت دائم ضروري مي‌دانيد، استفاده از اين روش مناسب مي‌باشد و با استفاده از آن مي‌توانيد در هنگام لودشدن برنامه، مجوزهاي خاصي را درخواست كنيد و در صورتي كه مجوز موردنظر داده نشود، از لود شدن برنامه جلوگيري كنيد.
به عنوان مثال به كد زير توجه كنيد:
publicClassMyClass
PublicsubNew
'Constructor is protected by the security call
EndSub
PublicSub MyMethod1()
'Method is protected by the security call
EndSub
EndClass

همان‌طور كه ملاحظه مي‌كنيد در سطح كلاس 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هاي خاص را كه با فيلدهاي خاصي موردنياز برنامه ما مي‌باشد، تعريف كنيم.
 

Principa

اين شيء، شي‌ء اساسي مكانيزم 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 در آن پوشه درست كنيد و كد زير را در آن بنويسيد:
<locationpath=" SampelDirectory">
<system.web>
<authorization>
<allowroles="Administrators,Developers"/>
<denyusers="*"/>
</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 AsString = "Jack"
Dim UsrRole
As
String = "Manager"
Dim UsrPrincipalPermission As
New PrincipalPermission(UsrName,UsrRole)

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