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.