Anasayfa / Asp.NET MVC / ASP.NET MVC XSS (Cross-Site Scripting)

ASP.NET MVC XSS (Cross-Site Scripting)

Cross-Site Scripting (XSS)  web uygulamasında tehlikeli bir rol göstermektedir ve buna göre de ele alınmalıdır. Bunu, tüm olası kanallardan girişi doğrulayarak yaparsak bu saldırıyı engellemiş olacağız. ASP.NET, daha etkili hale getirmek için genişletilebilecek bazı yerleşik istek doğrulamalarına sahiptir, ancak bu yaklaşım ASP.NET MVC uygulamasında geliştiricilereye kolaylık sağlaması açısından hedeflediğim yöntemi sizlerle paylaşıyor olacağım.

Aşağıdaki örnekten anlaşılacağı üzere saldırının engellemesini görmüş olacaksınız.

 

 public class XssAction
    {
        private static XssAction instance;
        public static XssAction Instance => instance = instance ?? new XssAction();
        public XssAction()
        {
            instance = this;
        }
        public void Invoke(ActionExecutingContext filterContext)
        {
            Dictionary<string, object> changeDictionary = new Dictionary<string, object>();
            foreach (var para in filterContext.ActionParameters)
            {
                if (para.Value?.GetType() == typeof(string))
                {

                    var value = para.Value as string;
                    if (!string.IsNullOrWhiteSpace(value))
                    {
                        value = Sanitizer.GetSafeHtmlFragment(value);
                        changeDictionary.Add(para.Key, value);
                    }
                }
                else if (para.Value != null)
                {
                    var ty = para.Value.ToString();
                    if (ty != null && (para.Value?.GetType().IsClass == true || ty.Contains("{")))
                    {
                        var clss = para.Value?.GetType();
                        var obj = clss.Assembly.CreateInstance(clss.FullName);
                        try
                        {
                            var vls = clss.GetProperties();
                            foreach (PropertyInfo item in vls)
                            {
                                var yvue = item.GetValue(para.Value, null).ToString();
                                var isxss = !string.IsNullOrEmpty(Regex.Match(yvue, @"<|>|(|)&lt|%3c|script")?.Value);
                                if (isxss)
                                {
                                    var vlue = Sanitizer.GetSafeHtmlFragment(item.GetValue(para.Value, null).ToString()).Replace("script", "");
                                    SetValue(obj, item.Name, vlue);
                                }
                                else
                                {
                                    SetValue(obj, item.Name, yvue);
                                }
                            }
                            changeDictionary.Add(para.Key, obj);

                        }
                        catch (Exception ex)
                        {
                            if (changeDictionary?.Count > 0)
                            {
                                changeDictionary.Clear();
                            }
                            Debug.Write("xss filter exception: " + ex.ToString() + "|||" + ty);
                        }

                    }
                }
            }

            foreach (var changePara in changeDictionary)
            {
                try
                {
                    filterContext.ActionParameters[changePara.Key] = changePara.Value;
                }
                catch (Exception ex)
                {
                    Debug.Write("xss filter exception:" + ex.ToString());
                    //throw;
                }
            }
        }
        
        public static Dictionary<string, object> ObjectToDictionary(object obj)
        {
            Dictionary<string, object> ret = new Dictionary<string, object>();

            foreach (PropertyInfo prop in obj.GetType().GetProperties())
            {
                string propName = prop.Name;
                var val = obj.GetType().GetProperty(propName).GetValue(obj, null);
                if (val != null)
                {
                    ret.Add(propName, val);
                }
                else
                {
                    ret.Add(propName, null);
                }
            }

            return ret;
        }
        public static bool IsType(Type type, string typeName)
        {
            if (type.ToString() == typeName)
                return true;
            if (type.ToString() == "System.Object")
                return false;

            return IsType(type.BaseType, typeName);
        }
        public static void SetValue(object entity, string fieldName, string fieldValue)
        {
            Type entityType = entity.GetType();

            PropertyInfo propertyInfo = entityType.GetProperty(fieldName);

            if (IsType(propertyInfo.PropertyType, "System.String"))
            {
                propertyInfo.SetValue(entity, fieldValue, null);

            }

            if (IsType(propertyInfo.PropertyType, "System.Boolean"))
            {
                propertyInfo.SetValue(entity, Boolean.Parse(fieldValue), null);

            }

            if (IsType(propertyInfo.PropertyType, "System.Int32"))
            {
                if (fieldValue != "")
                    propertyInfo.SetValue(entity, int.Parse(fieldValue), null);
                else
                    propertyInfo.SetValue(entity, 0, null);

            }

            if (IsType(propertyInfo.PropertyType, "System.Decimal"))
            {
                if (fieldValue != "")
                    propertyInfo.SetValue(entity, Decimal.Parse(fieldValue), null);
                else
                    propertyInfo.SetValue(entity, new Decimal(0), null);

            }

            if (IsType(propertyInfo.PropertyType, "System.Nullable`1[System.DateTime]"))
            {
                if (fieldValue != "")
                {
                    try
                    {
                        propertyInfo.SetValue(entity, (DateTime?)Convert.ToDateTime(fieldValue), null);
                    }
                    catch
                    {
                        propertyInfo.SetValue(entity, (DateTime?)DateTime.ParseExact(fieldValue, "yyyy-MM-dd HH:mm:ss", null), null);
                    }
                }
                else
                    propertyInfo.SetValue(entity, null, null);

            }

        }
    }

Aşağıdaki methodla da nereden çağıracağınızı da görebilirsiniz.

 public abstract class BaseController : Controller
{
        protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            XssAction.Instance.Invoke(filterContext);
            base.OnActionExecuting(filterContext);
        }
}

Bir saldırı yönteminin önüne geçmiş olduk.