确保 c# Assemby 是确定性的
Ensure that c# Assemby are deterministic
可以限制特定的类,例如Random或DateTime,或使用float 在 AppDomain 中。如果使用它们,是否可以通过反射检测到它?或者我们应该看看 IL 代码?
我想做一个插件系统,但我必须确保执行的代码是确定性的。关于如何处理它还有其他想法吗?
谢谢。
您可以使用 Cecil[*] 之类的内容查看 IL。但话又说回来,可以通过反射访问这些东西。
[*]:这会花费一些时间,提示您缓存结果...,这会引入一个漏洞,攻击者会在该漏洞中模仿缓存中的有效条目。
另一方面,您可以使用 sandbox without Reflection。您必须将其与上述方法结合起来。
然后,有一些方法可以模仿您所描述的行为...例如,您可以创建自己的 Random Number Generator (which is something totally deterministic, by the way) and seed it with the current time or other source of entropy(您可能想要拒绝对文件系统和网络的访问,并且甚至外围设备和其他系统状态 - 例如脚本可能会根据指针位置产生不同的结果)。
可以创建类型白名单来完成这项工作
readonly static List<string> WhiteList = new List<string>()
{
#region Basics
typeof(Boolean).FullName,
typeof(Char).FullName,
typeof(String).FullName,
typeof(Byte).FullName,
typeof(SByte).FullName,
typeof(UInt16).FullName,
typeof(Int16).FullName,
typeof(UInt32).FullName,
typeof(Int32).FullName,
typeof(UInt64).FullName,
typeof(Int64).FullName,
typeof(Decimal).FullName,
typeof(Double).FullName,
typeof(Single).FullName,
typeof(TimeSpan).FullName,
typeof(Array).FullName,
typeof(Enum).FullName,
#endregion
#region Exceptions
typeof(Exception).FullName,
typeof(NotImplementedException).FullName,
typeof(IOException).FullName,
#endregion
#region Delegates
typeof(Delegate).FullName,
#endregion
#region Parallel
typeof(Parallel).FullName,
#endregion
#region Conversions
typeof(Convert).FullName,
typeof(BitConverter).FullName,
#endregion
#region Streams
typeof(Stream).FullName,
typeof(MemoryStream).FullName,
typeof(BinaryReader).FullName,
typeof(BinaryWriter).FullName,
#endregion
#region Interfaces
typeof(IDisposable).FullName,
typeof(IComparable).FullName,
typeof(IConvertible).FullName,
typeof(IFormatProvider).FullName,
typeof(IFormattable).FullName,
typeof(IOrderedQueryable).FullName,
#endregion
#region Attributes
typeof(Attribute).FullName,
// Compilation JIT
typeof(CompilationRelaxationsAttribute).FullName,
typeof(RuntimeCompatibilityAttribute).FullName,
typeof(CompilerGeneratedAttribute).FullName,
#endregion
#region Generic Types
typeof(IDictionary<object,object>).Namespace+"."+typeof(IDictionary<object,object>).Name,
typeof(Dictionary<object,object>).Namespace+"."+typeof(Dictionary<object,object>).Name,
typeof(List<object>).Namespace+"."+typeof(List<object>).Name,
typeof(IList<object>).Namespace+"."+typeof(IList<object>).Name,
typeof(IEnumerable<object>).Namespace+"."+typeof(IEnumerable<object>).Name,
typeof(IEnumerator<object>).Namespace+"."+typeof(IEnumerator<object>).Name,
typeof(IOrderedEnumerable<object>).Namespace+"."+typeof(IOrderedEnumerable<object>).Name,
typeof(IOrderedQueryable<object>).Namespace+"."+typeof(IOrderedQueryable<object>).Name,
typeof(ICollection<object>).Namespace+"."+typeof(ICollection<object>).Name,
typeof(IComparable<object>).Namespace+"."+typeof(IComparable<object>).Name,
typeof(IEquatable<object>).Namespace+"."+typeof(IEquatable<object>).Name,
typeof(IObservable<object>).Namespace+"."+typeof(IObservable<object>).Name,
#endregion
};
const string WhiteListedNamespace = "XX.XXXXXXXXXX.";
/// <summary>
/// Check white list
/// </summary>
/// <param name="binary">Binary</param>
public static void CheckWhiteList(byte[] binary)
{
using (MemoryStream ms = new MemoryStream(binary))
{
AssemblyDefinition def = AssemblyDefinition.ReadAssembly(ms, new ReaderParameters(ReadingMode.Immediate));
List<string> ls = new List<string>();
foreach (ModuleDefinition mdef in def.Modules)
foreach (TypeReference tdef in mdef.GetTypeReferences())
{
if (!WhiteList.Contains(tdef.FullName) &&
!tdef.FullName.StartsWith(WhiteListedNamespace, StringComparison.InvariantCulture))
ls.Add(tdef.FullName);
}
if (ls.Count > 0)
throw (new TypeNotAllowedException(ls.ToArray()));
}
}
可以限制特定的类,例如Random或DateTime,或使用float 在 AppDomain 中。如果使用它们,是否可以通过反射检测到它?或者我们应该看看 IL 代码?
我想做一个插件系统,但我必须确保执行的代码是确定性的。关于如何处理它还有其他想法吗?
谢谢。
您可以使用 Cecil[*] 之类的内容查看 IL。但话又说回来,可以通过反射访问这些东西。
[*]:这会花费一些时间,提示您缓存结果...,这会引入一个漏洞,攻击者会在该漏洞中模仿缓存中的有效条目。
另一方面,您可以使用 sandbox without Reflection。您必须将其与上述方法结合起来。
然后,有一些方法可以模仿您所描述的行为...例如,您可以创建自己的 Random Number Generator (which is something totally deterministic, by the way) and seed it with the current time or other source of entropy(您可能想要拒绝对文件系统和网络的访问,并且甚至外围设备和其他系统状态 - 例如脚本可能会根据指针位置产生不同的结果)。
可以创建类型白名单来完成这项工作
readonly static List<string> WhiteList = new List<string>()
{
#region Basics
typeof(Boolean).FullName,
typeof(Char).FullName,
typeof(String).FullName,
typeof(Byte).FullName,
typeof(SByte).FullName,
typeof(UInt16).FullName,
typeof(Int16).FullName,
typeof(UInt32).FullName,
typeof(Int32).FullName,
typeof(UInt64).FullName,
typeof(Int64).FullName,
typeof(Decimal).FullName,
typeof(Double).FullName,
typeof(Single).FullName,
typeof(TimeSpan).FullName,
typeof(Array).FullName,
typeof(Enum).FullName,
#endregion
#region Exceptions
typeof(Exception).FullName,
typeof(NotImplementedException).FullName,
typeof(IOException).FullName,
#endregion
#region Delegates
typeof(Delegate).FullName,
#endregion
#region Parallel
typeof(Parallel).FullName,
#endregion
#region Conversions
typeof(Convert).FullName,
typeof(BitConverter).FullName,
#endregion
#region Streams
typeof(Stream).FullName,
typeof(MemoryStream).FullName,
typeof(BinaryReader).FullName,
typeof(BinaryWriter).FullName,
#endregion
#region Interfaces
typeof(IDisposable).FullName,
typeof(IComparable).FullName,
typeof(IConvertible).FullName,
typeof(IFormatProvider).FullName,
typeof(IFormattable).FullName,
typeof(IOrderedQueryable).FullName,
#endregion
#region Attributes
typeof(Attribute).FullName,
// Compilation JIT
typeof(CompilationRelaxationsAttribute).FullName,
typeof(RuntimeCompatibilityAttribute).FullName,
typeof(CompilerGeneratedAttribute).FullName,
#endregion
#region Generic Types
typeof(IDictionary<object,object>).Namespace+"."+typeof(IDictionary<object,object>).Name,
typeof(Dictionary<object,object>).Namespace+"."+typeof(Dictionary<object,object>).Name,
typeof(List<object>).Namespace+"."+typeof(List<object>).Name,
typeof(IList<object>).Namespace+"."+typeof(IList<object>).Name,
typeof(IEnumerable<object>).Namespace+"."+typeof(IEnumerable<object>).Name,
typeof(IEnumerator<object>).Namespace+"."+typeof(IEnumerator<object>).Name,
typeof(IOrderedEnumerable<object>).Namespace+"."+typeof(IOrderedEnumerable<object>).Name,
typeof(IOrderedQueryable<object>).Namespace+"."+typeof(IOrderedQueryable<object>).Name,
typeof(ICollection<object>).Namespace+"."+typeof(ICollection<object>).Name,
typeof(IComparable<object>).Namespace+"."+typeof(IComparable<object>).Name,
typeof(IEquatable<object>).Namespace+"."+typeof(IEquatable<object>).Name,
typeof(IObservable<object>).Namespace+"."+typeof(IObservable<object>).Name,
#endregion
};
const string WhiteListedNamespace = "XX.XXXXXXXXXX.";
/// <summary>
/// Check white list
/// </summary>
/// <param name="binary">Binary</param>
public static void CheckWhiteList(byte[] binary)
{
using (MemoryStream ms = new MemoryStream(binary))
{
AssemblyDefinition def = AssemblyDefinition.ReadAssembly(ms, new ReaderParameters(ReadingMode.Immediate));
List<string> ls = new List<string>();
foreach (ModuleDefinition mdef in def.Modules)
foreach (TypeReference tdef in mdef.GetTypeReferences())
{
if (!WhiteList.Contains(tdef.FullName) &&
!tdef.FullName.StartsWith(WhiteListedNamespace, StringComparison.InvariantCulture))
ls.Add(tdef.FullName);
}
if (ls.Count > 0)
throw (new TypeNotAllowedException(ls.ToArray()));
}
}