简体   繁体   中英

loading loose XAML drawing securely

A C# Windows application would like to load vector drawings that are stored in loose XAML files without allowing arbitrary code execution.

I am already loading such drawings from resources in linked assemblies over which I have control. However, I would like to also support loading loose XAML files. I imagine you can use XAML access control to limit the objects that can be instantiated in such XAML? Ideally, I would limit the loader to instantiating only the drawing primitives that are in the files we know about. It's ok that it would reject a file that has new drawing primitives in it that we have not whitelisted.

Is this a standard thing already supported by an API? Because I could not find it. Otherwise, does anyone have an example or beginnings of an example? This is for a free open source project and any help getting started would probably cut down the research I need to do by a lot.

The following seems to do a pretty decent job of white listing specific types in a XAML load:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Windows.Controls;
using System.Windows.Media;
using System.Xaml;
using System.Xml;

namespace TestXamlLoading
{
    internal class SchemaContext : XamlSchemaContext
    {
        // map from XAML element name to required namespace (currently always the same)
        private static readonly Dictionary<string, string> AllowedTypes = new Dictionary<string, string>();

        static SchemaContext()
        {
            // questionable: <Image> is used in some drawing XAML, should review it
            foreach (string name in new[]
            {
                "Canvas", "Compound", "Ellipse", "GradientStop", "GradientStopCollection", "Group", "Line",
                "LinearGradientBrush", "MatrixTransform", "Path", "PathGeometry", "Polygon",
                "RadialGradientBrush", "Rectangle", "RotateTransform", "ScaleTransform", "SkewTransform", "TextBlock",
                "TransformGroup", "TranslateTransform"
            })
            {
                AllowedTypes[name] = "http://schemas.microsoft.com/winfx/2006/xaml/presentation";
            }
        }

        public SchemaContext(IEnumerable<Assembly> referenceAssemblies, XamlSchemaContextSettings settings) : base(
            referenceAssemblies, settings)
        {
            // no code
        }

        protected override XamlType GetXamlType(string xamlNamespace, string name, params XamlType[] typeArguments)
        {
            if (!AllowedTypes.TryGetValue(name, out string requiredNamespace) || xamlNamespace != requiredNamespace)
            {
                throw new Exception($"disallowed instantiation of '{xamlNamespace}' '{name}' from XAML");
            }

            return base.GetXamlType(xamlNamespace, name, typeArguments);
        }
    }

    internal class Program
    {
        [STAThreadAttribute]
        private static void Main(string[] args)
        {
            bool shouldFail = TestLoad("..\\..\\..\\badfile.xaml");
            Debug.Assert(!shouldFail);
            bool shouldSucceed = TestLoad("..\\..\\..\\goodfile.xaml");
            Debug.Assert(shouldSucceed);
        }

        private static bool TestLoad(string path)
        {
            Stream inputStream = new FileStream(path, FileMode.Open);
            XmlReader xmlReader = new XmlTextReader(inputStream);
            Assembly[] referenceAssemblies =
            {
                // these are two separate assemblies which contain all the types we allow
                Assembly.GetAssembly(typeof(Canvas)),
                Assembly.GetAssembly(typeof(TransformGroup))
            };
            XamlSchemaContextSettings settings = new XamlSchemaContextSettings();
            XamlSchemaContext schemaContext = new SchemaContext(referenceAssemblies, settings);
            try
            {
                XamlReader reader = new XamlXmlReader(xmlReader, schemaContext);
                Canvas canvas = (Canvas) System.Windows.Markup.XamlReader.Load(reader);
            }
            catch (Exception e)
            {
                Debug.WriteLine(e);
                return false;
            }

            return true;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM