جلوگیری از حمله Cross-Site در ASP.NET Core – جلسه ۵۸

cross-site-attacks-in-asp-net-core-Session58

در این جلسه به بررسی حمله Cross-Site و آموزش روش جلوگیری از این حمله در ASP.NET Core خواهیم پرداخت . به این نوع حمله که با عنوان XSRF/CSRF Attacks نیز شناخته میشود، در واقع ارسال درخواست مشکوک و مخرب به وب اپلیکشن مورد نظر (مانند اپلیکشن بانک و یا پرتال‌های حاوی اطلاعات مالی) از سوی یک وب اپلیکیشن یا صفحه ثالث توسط مرورگر مورد اعتماد وب اپلیکیشن مورد نظر گفته میشود. در این نوع حمله، وب سایت و یا وب اپلیکشن مخرب از احراز هویت قبلی کاربر در پرتال مورد هدف جهت برقراری و ثبت درخواست استفاده میکند.

حمله Cross-Site چیست؟

حمله Cross-Site و یا XSRF/CSRF Attacks به ارسال درخواست مخرب به وب اپلیکشن مورد نظر توسط وب اپلیکشن ثالث از طریق مرورگر مورد اعتماد وب اپلیکیشن هدف گفته می‌شود. این حمله درخواست مشکوک را با استفاده از احراز هویت قبلی کاربر توسط مرورگر مورد اعتماد وب اپلیکیشن هدف ثبت می‌کند.

برای توضیح بیشتر، شما فرض کنید که یک ایمیل با متن زیر دریافت میکنید.

cross-site-attack-sample

حال با توجه به جذاب بودن موضوع، کاربر ممکن است وسوسه گردد و برای دریافت جایزه خود بروی کلید مربوطه کلیک نماید. و این در واقع زمانی است که حمله Cross-Site صورت می‌پذیرد.

چرا که در صورتی که قبلا با توجه به این مثال در پرتال بانکی خود احراز هویت کرده باشید، کد زیر که در واقع پشت ظاهر و پیام جذاب مخفی شده است، اجرا میگردد. در واقع صفحه فوق حاوی کد زیر میباشد.

<h1>Congratulations! You're a Winner!</h1>
<form action="https://yourbank.com/transffer" method="post">
	<input type="hidden" name="Transaction" value=“transfer" />
	<input type="hidden" name=“Receiver" value=“4154-45445-4444" />
	<input type="hidden" name="Amount" value=“999999" />
 	<input type="submit" value="Click to collect your prize!" />
</form>

و همانگونه که مشاهده میکنید با کلیک برر‌وی دکمه مورد نظر، درخواست انتقال پول از حساب شما به حساب مقصد که متعلق به شخص حمله کننده میباشد با مبلغ ذکر شده ثبت میگردد. البته ما برای درک ساده‌تر این حمله یک مثال ساده ذکر نمودیم و در واقع موضوع میتواند بسیار پیچیده‌تر باشد.

جلوگیری از حمله Cross-Site در ASP.NET Core

برای جلوگیری از XSRF/CSRF Attacks روشهای متفاوتی وجود دارد و روش ارائه شده در این جلسه، تنها راه کافی برای تامین امنیت وب اپلیکیشن شما نخواهد بود. ما در این جلسه برای جلوگیری از حمله Cross-Site از توکن Anti Forgery استفاده میکنیم. این توکن به صورت پیشفرض از طرف فرم‌های درون View با متد Post در ASP.NET Core به کنترلر ارسال میگردد. به عبارت دیگر به صورت پیشفرض مقدار تگ هلپر asp-antiforgery در فرم‌های درون نما، برابر با True میباشد.

همچنین برای جلوگیری از این حمله در کنترلر، برای اکشن متدهای روش Post می‌توانیم از خصوصیت ValidateAntiForgeryToken استفاده نماییم.

ما درون وب اپلیکیشن مربوط به این دوره آموزشی، برای ایمن‌سازی آن نسبت به حمله Cross-Site از خصوصیت (Attribute) ذکر شده استفاده نمودیم. کد زیر مربوط به کنترلر مورد نظر میباشد.

namespace DailyCostWebApplication.Controllers
{
    public class CostController : Controller
    {
        private readonly ICostRepository costRepository;
        private readonly ICategoryRepository categoryRepository;
        private readonly IWebHostEnvironment webHostEnvironment;

        public CostController(ICostRepository _costRepository, ICategoryRepository _categoryRepository, 
            IWebHostEnvironment _webHostEnvironment)
        {
            costRepository = _costRepository;
            categoryRepository = _categoryRepository;
            webHostEnvironment = _webHostEnvironment;
        }

        [HttpGet]
        public IActionResult Create()
        {
            LoadDropdownList();
            return View();
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Create(CreateCostViewModel model)
        {
            if (ModelState.IsValid)
            {
                Cost cost = new()
                {
                    Amount = model.Amount,
                    Comment = model.Comment,
                    RegisteredDate = model.RegisteredDate,
                    CategoryID = model.CategoryID,
                    PaymentMethod = model.PaymentMethod
                };
                if(model.UploadFile != null)
                {
                    cost.InvoiceImagePath = UploadFile(model.UploadFile);
                }
                costRepository.Create(cost);
                return RedirectToAction("Index");
            }
            LoadDropdownList();
            return View(model);
        }
        [HttpGet]
        public IActionResult Index(string searchby, string searchfor, int? page, string sortby)
        {
            var costs = costRepository.GetCostList(searchby, searchfor,sortby).ToPagedList(page ?? 1, 5);
            return View(costs);
        }
        [HttpGet]
        public IActionResult Detail(int id)
        {
            var cost = costRepository.GetCostByID(id);
            return View(cost);
        }
        [HttpGet]
        public IActionResult Update(int id)
        {
            var cost = costRepository.GetCostByID(id);
            UpdateCostViewModel model = new()
            {
                ID = cost.ID,
                Amount = cost.Amount,
                RegisteredDate = cost.RegisteredDate,
                Comment = cost.Comment,
                CategoryID = cost.CategoryID,
                PaymentMethod = cost.PaymentMethod,
                ExsitingFile = cost.InvoiceImagePath
            };
            LoadDropdownList();
            return View(model);
        }
        [HttpPost]
        [ValidateAntiForgeryToken]
        public IActionResult Update(UpdateCostViewModel model)
        {
            if (ModelState.IsValid)
            {
                Cost UpdatedCost = costRepository.GetCostByID(model.ID);
                UpdatedCost.Amount = model.Amount;
                UpdatedCost.RegisteredDate = model.RegisteredDate;
                UpdatedCost.Comment = model.Comment;
                UpdatedCost.CategoryID = model.CategoryID;
                UpdatedCost.PaymentMethod = model.PaymentMethod;
                if(model.UploadFile != null)
                {
                    if(UpdatedCost.InvoiceImagePath != null)
                    {
                        string ExitingFile = Path.Combine(webHostEnvironment.WebRootPath, "images", UpdatedCost.InvoiceImagePath);
                        System.IO.File.Delete(ExitingFile);
                    }
                    UpdatedCost.InvoiceImagePath = UploadFile(model.UploadFile);
                }
                costRepository.Update(UpdatedCost);
                return RedirectToAction("Index");
            }
            LoadDropdownList();
            return View(model);
        }
        [ValidateAntiForgeryToken]
        [HttpPost]
        public IActionResult Delete(int id)
        {
            Cost cost = costRepository.GetCostByID(id);
            if (cost.InvoiceImagePath != null)
            {
                string ExitingFile = Path.Combine(webHostEnvironment.WebRootPath, "images", cost.InvoiceImagePath);
                System.IO.File.Delete(ExitingFile);
            }
            costRepository.Delete(id);
            return RedirectToAction("index");
        }
        private void LoadDropdownList()
        {
            var Categories = categoryRepository.GetAllCategories();
            List<SelectListItem> CatList = new();
            CatList.Add(new SelectListItem("Select a Category", "-1"));
            foreach (var category in Categories)
            {
                CatList.Add(new SelectListItem(category.CategoryName, category.ID.ToString()));
            }
            List<SelectListItem> PaymentList = new();
            PaymentList.Add(new SelectListItem("Select a Payment Method", ""));
            var PaymentMethod = Enum.GetValues(typeof(PaymentMethods)).Cast<PaymentMethods>().ToList();
            for (var i = 0; i < PaymentMethod.Count(); i++)
            {
                PaymentList.Add(new SelectListItem(PaymentMethod[i].ToString(), i.ToString()));
            }
            ViewBag.Categories = CatList;
            ViewBag.PaymentMethods = PaymentList;
        }
        private string UploadFile(IFormFile formFile)
        {
            string UniqueFileName = Guid.NewGuid().ToString() + "-" + formFile.FileName;
            string TargetPath = Path.Combine(webHostEnvironment.WebRootPath, "images", UniqueFileName);
            using (var stream = new FileStream(TargetPath, FileMode.Create))
            {
                formFile.CopyTo(stream);
            }
            return UniqueFileName;
        }


    }
 
}

و همانطور که مشاهده میکنید برای تمامی اکشن متدهای نوع Post از خصوصیت ValidateAntiForgeryToken استفاده نمودیم.

در صورت نیاز به جزئیات بیشتر، میتوانید ویدئو آموزشی این جلسه را تماشا نمایید. همچنین برای آگاهی از جلسات بعدی این دوره آموزشی، ما را در اینستاگرام، تلگرام، یوتیوب و آپارات دنبال کنید. ضمنا لیست کامل جلسات در این قسمت در دسترس شما میباشد و سورس کد این جلسه را میتوانید از GitHub ما دانلود نمایید.

تماشای ویدیو در یوتیوب ما

دانلود اسلایدهای آموزشی این جلسه از اینجا

برچسب ها

0 0 رای ها
امتیازدهی به مقاله
اشتراک در
اطلاع از
guest
0 نظرات
بازخورد (Feedback) های اینلاین
مشاهده همه دیدگاه ها
0
افکار شما را دوست داریم، لطفا نظر دهید.x