lundi 21 août 2017

Reflection to walk every string property in class

I want to store user's input on my database. The user can write texts with html tags to style his texts.

I want to remove potential malware like javascript and so on. Instead of checking every string property in the class by hand, I want an object-extension which walks through every string property and replace potential malware...

My approach supports:

class TestClassStringProperties
{
    public TestClassStringProperties()
    {
        MyProp = "123";
    }

    public string MyProp { get; set; }
}

class TestClassNestedProperties
{
    public TestClassNestedProperties()
    {
        NestedType = new TestClassStringProperties();
        MyProp = "123";
    }

    public string MyProp { get; set; }
    public TestClassStringProperties NestedType { get; set; }
}

class TestWithCollectionOfNestedProperties
{
    public TestWithCollectionOfNestedProperties()
    {
        NestedPropertiesCollection = new List<TestClassStringProperties>();
    }

    public ICollection<TestClassStringProperties> NestedPropertiesCollection { get; set; }
}

But it fails with this:

class TestClassWithStringCollection
{
    public TestClassWithStringCollection()
    {
        Strings = new List<string> {"123", "123", "123", "123"};
    }

    public ICollection<string> Strings { get; set; }
}

Extensionmethod:

public static class ObjectExtension
{
    private static HashSet<int> _vistedNestedTypes;

    public static void SanitizeJavaScriptFromAllPublicStringProps(this  object obj)
    {
        _vistedNestedTypes = new HashSet<int>();
        Sanitize(obj);
    }

    private static void Sanitize(object obj)
    {
        var properties = obj.GetType()
            .GetProperties(BindingFlags.Public | BindingFlags.Instance);
        if (ProduceStackOverflow(obj))
            return;
        foreach (var property in properties)
        {
            CollectionBehaviour(obj, property);
            if (property.PropertyType.GetTypeInfo().IsClass)
                if (property.PropertyType == typeof(string))
                {
                    // If not writable then cannot null it; if not readable then cannot check it's value
                    if (!property.CanWrite || !property.CanRead)
                        continue;
                    var mget = property.GetGetMethod(false);
                    var mset = property.GetSetMethod(false);

                    // Get and set methods have to be public
                    if (mget == null || mset == null)
                        continue;
                    property.SetValue(obj, "HACKED"); // I remove evil code at this place...
                }
                else
                {
                    NestedTypeBehaviour(obj, property);
                }
        }
    }

    private static void NestedTypeBehaviour(object obj, PropertyInfo p)
    {
        var pp = p.GetValue(obj, null);
        if (pp != null && !_vistedNestedTypes.Contains(pp.GetHashCode()))
        {
            Sanitize(pp);
            _vistedNestedTypes.Add(pp.GetHashCode());
        }
    }

    private static void CollectionBehaviour(object obj, PropertyInfo p)
    {
        if (typeof(IEnumerable<object>).IsAssignableFrom(p.PropertyType))
        {
            var items = (IEnumerable) p.GetValue(obj, null);
            var enumerable = items as IList<object> ?? items.Cast<object>().ToList();
            var cnt = enumerable.Count;
            for (int i = 0; i < cnt; i++)
            {
                var a = enumerable[i];
                Sanitize(a);
                enumerable[i] = a;
            }
        }
    }

    private static bool ProduceStackOverflow(object obj)
    {
        if (!_vistedNestedTypes.Contains(obj.GetHashCode()))
        {
            _vistedNestedTypes.Add(obj.GetHashCode());
            return false;
        }
        return true;
    }
}

After executing the extension, my strings are "123" in the collection and not "HACKED" as I would expect.

Thank you in advance.





Aucun commentaire:

Enregistrer un commentaire