ایجاد یک ActionFilter جهت تمیز کردن اطلاعات ورودی در ASP.NET Core
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: یک دقیقه

در  ASP.NET Core کار جلوگیری از حملات  XSS بر عهده برنامه نویس گذاشته شده‌است و مانند نسخه‌های قبلی، Request Validation یا اعتبارسنجی درخواست‌ها به صورت توکار در آن وجود ندارد. برای اطلاعات بیشتر به این مقاله مراجعه کنید.

هرچند ASP.NET Core داده‌ها را هنگام نمایش، encode می‌کند و عملا بسیاری از حملات خنثی می‌شوند، اما در صورتیکه بخواهیم داده‌های غیر مطمئن، در بانک اطلاعاتی نیز ذخیره نشوند، باید آنها را ارزیابی کنیم. یکی از روش‌های مقابله‌ی با این حملات، تمیز کردن اطلاعات ورودی کاربر است. در ادامه به ایجاد یک ActionFilter می‌پردازیم تا این کار را برای ورودی‌های یک Action Method انجام دهد:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    public class SanitizeInputAttribute : ActionFilterAttribute
    {
        var sanitizer = new Ganss.XSS.HtmlSanitizer(); 

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (filterContext.ActionArguments != null)
            {
                foreach (var parameter in filterContext.ActionArguments)
                {
                    var properties = parameter.Value.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public)
                        .Where(x => x.CanRead && x.CanWrite && x.PropertyType == typeof(string) && x.GetGetMethod(true).IsPublic && x.GetSetMethod(true).IsPublic);
                    foreach (var propertyInfo in properties)
                    {
                        if (propertyInfo.GetValue(parameter.Value) != null)
                            propertyInfo.SetValue(parameter.Value,
                                sanitizer.Sanitize(propertyInfo.GetValue(parameter.Value).ToString()));  
                    }
                }
            }
        }
    }
در این فیلتر، از کتابخانه
HtmlSanitizer برای تمیز کردن اطلاعات استفاده کرده‌ایم. ابتدا تمام ورودی‌های اکشن متد را خوانده و سپس ورودی‌هایی را که از نوع  string هستند، پیدا کرده و مقدار فعلی آنها را با مقدار sanitize شده، جایگزین می‌کند. بنابراین اگر در رشته‌ی ورودی، عبارت یا تگ خطرناک یا غیر مجازی باشد، حذف می‌گردد.

برای استفاده از این فیلتر کافی است به صورت زیر عمل کنیم:
[SanitizeInput]
public IActionResult Add(GroupDto dto)
  • #
    ‫۳ سال و ۲ ماه قبل، شنبه ۲۹ خرداد ۱۴۰۰، ساعت ۱۸:۰۳
    سلام. این متد درصورتی درست کار می‌کند که پارامتر ورودی یک مدل باشد و درصورتیکه پارامتر ورودی از نوع string باشد درست کار نمی‌کند و آن را تغییر نمی‌دهد. 
      [SanitizeInput] public IActionResult Add (string address)
    • #
      ‫۳ سال و ۲ ماه قبل، شنبه ۲۹ خرداد ۱۴۰۰، ساعت ۱۸:۲۵
      در مورد کوئری‌استرینگ‌ها:
      var address = filterContext.HttpContext.Request.QueryString["address"] as string;
      filterContext.ActionParameters["address"] = sanitizer.Sanitize(address);
    • #
      ‫۳ سال و ۲ ماه قبل، شنبه ۲۹ خرداد ۱۴۰۰، ساعت ۱۹:۵۹
      نسخه کاملتر این متد به صورت زیر می‌باشد که ورودی  string را هم پوشش می‌دهد :
       [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
          public class SanitizeInputAttribute : ActionFilterAttribute
          {
              private readonly ISanitizer _sanitizer;
      
              public SanitizeInputAttribute()
              {
                  _sanitizer = new Sanitizer();
              }
      
              public override void OnActionExecuting(ActionExecutingContext filterContext)
              {
                  if (filterContext.ActionArguments != null)
                  {
                      foreach (var parameter in filterContext.ActionArguments.ToList())
                      {
                          if (parameter.Value != null)
                          {
                              var type = parameter.Value.GetType();
                              if (type == typeof(string))
                              {
                                 var sanitized = _sanitizer.Sanitize(parameter.Value.ToString());
                                 filterContext.ActionArguments[parameter.Key] = sanitized;
                              }
                              else
                              {
                                  var properties = parameter.Value.GetType()
                                      .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                                      .Where(x => x.CanRead && x.CanWrite && x.PropertyType == typeof(string) &&
                                                  x.GetGetMethod(true).IsPublic && x.GetSetMethod(true).IsPublic);
      
      
      
                                  foreach (var propertyInfo in properties)
                                  {
                                      if (propertyInfo.GetValue(parameter.Value) != null)
                                          propertyInfo.SetValue(parameter.Value,
                                              _sanitizer.Sanitize(propertyInfo.GetValue(parameter.Value).ToString()));
                                  }
                              }
                          }
                      }
                  }
      
              }
          }

  • #
    ‫۲ سال و ۱۰ ماه قبل، یکشنبه ۲۵ مهر ۱۴۰۰، ساعت ۱۹:۳۹
    نحوه ثبت IHtmlSanitizer درIoc :
    IHtmlSanitizer sanitizer = new HtmlSanitizer();
    services.AddSingleton(sanitizer);