[Remoting]dotNet Framework升级后Remoting信道使用的安全问题
[Remoting]dotNet Framework升级后Remoting信道使用的安全问题
编写者:郑昀@UltraPower |
dotNet Framwork 1.1 关键字:Channel,remoting |
编写时间: |
摘要:.NET Framework升级之后,Remoting中的事件就需要对信道进行特别的设置,要自己创建BinaryServerFormatterSinkProvider类的实例,并且将其TypeFilterLevel设为TypeFilterLevel.Full,这是.NET 1.1中增强了安全设置后必须要做的事情。
引子:
现在使用以前在dotNET Framework1.0下编写的例子代码时,Remoting常常会在使用Channel时发生异常,错误如下所示:
中文错误报告以及错误堆栈 |
System.Security.SecurityException: 不允许类型 System.DelegateSerializationHolder 和从中派生的类型(例如 System.DelegateSerializationHolder)在此安全级别上被反序列化。 Server stack trace: at System.Runtime.Serialization.FormatterServices.CheckTypeSecurity(Type t, TypeFilterLevel securityLevel) at System.Runtime.Serialization.Formatters.Soap.ObjectReader.CheckSecurity(ParseRecord pr) |
英文错误报告 |
[SecurityException: Type System.DelegateSerializationHolder and the types derived from it (such as System.DelegateSerializationHolder) are not permitted to be deserialized at this security level.] |
这个错误是因为.NET Framework升级到1.1后,加强了安全设置导致的。
错误重现:
我是在下载并编译使用以前MSDN旧版本的RemSSPI.Exe代码(该文章在http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/remsspi.asp,是讲解如何穿越Remoting边界提供安全认证的。它已经更新了,RemSSPI.exe例子已经纠正了这个错误)时,遇到这个错误的。
异常发生在
REMSSPI\Microsoft\Samples\Security\SSPI\Sample\ControlPanel\Client
的MainForm.cs下面这句话上:
_ClientSecurity.SignedMessageEvent = new Microsoft.Samples.Security.SSPI.Sample.ClassLibrary.Client.SignedMessageDelegate(this.SignedMessage); |
_ClientSecurity对象是这么创建的:
_ClientSecurity = (Microsoft.Samples.Security.SSPI.Sample.ClassLibrary.Client.Security)Activator.GetObject(typeof(Microsoft.Samples.Security.SSPI.Sample.ClassLibrary.Client.Security), clientURL); |
这时候,他所使用的信道创建方法如下所示:
ChannelServices.RegisterChannel(new HttpChannel(Convert.ToInt32(txtClientPort.Text))); |
////////////////////////////////////////////////////////// BinaryServerFormatterSinkProvider serverProv = new BinaryServerFormatterSinkProvider(); serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; BinaryClientFormatterSinkProvider clientProv = new BinaryClientFormatterSinkProvider(); IDictionary props = new Hashtable(); props["port"] = Convert.ToInt32(txtClientPort.Text); HttpChannel chan = new HttpChannel(props, clientProv, serverProv); /// // |
方可。
另外一个例子也可以重现本错误:http://download.microsoft.com/download/MSPressPub/6172/1.0/W98NT42KMeXP/EN-US/Remoting.exe
原因:
RemotingFAQ 中讲到:
当你使用客户端激活的对象、事件或者委托时,在.NET Framework 1.1下你会遇到以下两种错误:
· System.Security.SecurityException.
Type System.DelegateSerializationHolder and the types derived from it (such as System.DelegateSerializationHolder) are not permitted to be deserialized at this security level.
· System.Runtime.Serialization.SerializationException
Because of security restrictions, the type System.Runtime.Remoting.ObjRef cannot be accessed.
要想回到以前的默认模式,就是允许跨越Remoting边界传递委托和对象引用,你必须改变“typeFilterLevel”。
微软的正式解释:
gotdotnet也正式谈到了这个问题,《Secure Serialization in .NET Remoting》;你也可以在这里找到这篇文档的中文翻译::
这一问题影响到的APIs有:
System.Runtime.Serialization.ISerializable
System.Runtime.Remoting.ObjRef
System.Runtime.Remoting.Lifetime.ILease
System.Runtime.Remoting.Lifetime.ISponsor
System.Runtime.Remoting.Contexts.IContributeEnvoySink
System.Runtime.Remoting.Channels.SoapServerFormatterSinkProvider
System.Runtime.Remoting.Channels.BinaryServerFormatterSinkProvider
依赖于运行时类型验证的远程处理系统必须反序列化一个远程流,然后才能开始使用它,未经授权的客户端可能会试图利用反序列化这一时机。为了免受这种攻击,.NET 远程处理提供了两个自动反序列化级别:Low 和 Full。Low(默认值)防止反序列化攻击的方式是,在反序列化时,只处理与最基本的远程处理功能关联的类型,如自动反序列化远程处理基础结构类型、有限的系统实现类型集和基本的自定义类型集。Full 反序列化级别支持远程处理在所有情况下支持的所有自动反序列化类型。
警告 不要以为控制反序列化是应用程序需要的唯一安全机制。在分布式应用程序中,即使严格控制序列化也不能防止这种危险的发生:即未经授权的客户端截获通信内容,然后以某种方式利用该通信内容,即使只是向其他用户显示数据,也会造成损害。因此,虽然 Low 反序列化级别对某些基于自动反序列化的攻击类型提供了一定的保护,但您仍然必须考虑是否使用身份验证和加密来为您的数据提供完全的保护。有关详细信息,请参见安全性。
· 如果应用程序需要使用仅在 Full 反序列化级别才可用的远程处理功能,您必须提供身份验证的类型和必要的加密级别,以保护任何在使用远程方案中的这些高级功能时可能遭受风险的资源。
解决之道:
您可以通过编程方式或使用应用程序配置文件设置反序列化级别。
以编程方式设置反序列化级别
若要以编程方式设置反序列化级别,请在创建时将以下属性传递给 SoapServerFormatterSinkProvider 对象或 BinaryServerFormatterSinkProvider 对象。然后,当该值插入到接收链中时,远程处理系统将在格式化程序上设置该值。以下示例说明如何在宿主应用程序域中将反序列化级别设置为 Full。
[C#]
// Creating a custom formatter for a TcpChannel sink chain.
BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
provider.TypeFilterLevel = TypeFilterLevel.Full;
// Creating the IDictionary to set the port on the channel instance.
IDictionary props = new Hashtable();
props["port"] = 8085;
// Pass the properties for the port setting and the server provider in the server chain argument. (Client remains null here.)
TcpChannel chan = new TcpChannel(props, null, provider);
[Visual Basic]
' Creating a custom formatter for your TcpChannel sink chain.
Dim provider As New BinaryServerFormatterSinkProvider()
provider.TypeFilterLevel = TypeFilterLevel.Full
' Creating the IDictionary to set the port on the channel instance.
IDictionary props = new Hashtable()
props("port") = 8085
' Pass the properties for the port setting and the server provider in the server chain argument. (Client remains null here.)
Dim chan As New TcpChannel(props, null, provider)
使用应用程序配置文件设置反序列化级别
若要使用配置文件设置反序列化级别,必须显式指定 <formatter> 元素的 typeFilterLevel 属性。虽然这通常是在服务器端指定的,但您还必须为注册来侦听回调的客户端上的任何信道指定这一属性,以控制其反序列化级别。以下示例为应用程序域中的 SoapFormatter 和 BinaryFormatter 显式地将反序列化级别设置为 Low。
<configuration>
<system.runtime.remoting>
<application>
<service>
<wellknown
type="ServiceType, common"
objectUri="ServiceType.soap"
mode="Singleton"
/>
</service>
<channels>
<channel ref="http">
<serverProviders>
<provider ref="wsdl" />
<formatter ref="soap" typeFilterLevel="Low" />
<formatter ref="binary" typeFilterLevel="Low" />
</serverProviders>
</channel>
</channels>
</application>
</configuration>
更多信息:
BinaryServerFormatterSinkProvider 类
为使用 BinaryFormatter 的服务器格式化程序信道接收器提供程序提供实现。
备注
信道接收器通过 IServerChannelSinkProvider 接口的实现连接到服务器信道。所有远程处理服务器信道均提供以 IServerChannelSinkProvider 为参数的构造函数。
信道接收器提供程序存储在一个链中,在向信道构造函数传递外部信道接收器提供程序之前,用户负责将所有的信道接收器提供程序链接在一起。为此,IServerChannelSinkProvider 提供了名为 Next 的属性。当在一个配置文件中提供了多个信道接收器提供程序时,远程处理结构将这些程序按在配置文件中找到的顺序链接起来。在 RemotingConfiguration.Configure 调用过程中创建信道时,将创建信道接收器提供程序。
格式化程序接收器在运行时使用接收器配置属性来配置信道。接收器属性可在配置文件中指定,或在 IDictionary 中以编程方式指定。在配置文件中,所有值都由字符串表示,但是当以编程方式生成属性 IDictionary 时,值类型可以用它们的本机值或字符串指定。
BinaryServerFormatterSinkProvider.TypeFilterLevel 属性
注意:此命名空间、类或成员仅在 .NET Framework 1.1 版中受支持。
获取或设置 BinaryServerFormatterSink 所执行的自动反序列化的 TypeFilterLevel。
.NET Framework 安全性:
对直接调用方完全信任。部分受信任的代码不能使用此成员。有关更多信息,请参阅在部分受信任的代码中使用库
编写者:郑昀@UltraPower