做项目不得不考虑安全问题,但是在Remoting应用中我似乎没有找到象WebService那样现成可用的防止非授权人员随意调用的方法和验证安全机制。当然,简单一点的可以通过Remoting客户端传输一些验证代码,然后在服务端验证这些代码的合法性,以实现是否安全授权调用,但是总觉得这样比较麻烦。我也见有些人主动把客户端的IP地址获取后主动送入到Remotin g服务端验证以便识别是否合法,其实原理跟上面的是一样的道理,我觉得这样传送很容易让别人仿造一些数据送入,从而轻易获得合法调用。当然以上数据可以通过把数据特殊的加密和解密也能得到比较好的安全性。在这里我是想介绍另外一种安全机制,即构建Remoting“防火墙”。
做项目不得不考虑安全问题,但是在Remoting应用中我似乎没有找到象WebService那样现成可用的防止非授权人员随意调用的方法和验证安全机制。当然,简单一点的可以通过Remoting客户端传输一些验证代码,然后在服务端验证这些代码的合法性,以实现是否安全授权调用,但是总觉得这样比较麻烦。我也见有些人主动把客户端的IP地址获取后主动送入到Remotin g服务端验证以便识别是否合法,其实原理跟上面的是一样的道理,我觉得这样传送很容易让别人仿造一些数据送入,从而轻易获得合法调用。当然以上数据可以通过把数据特殊的加密和解密也能得到比较好的安全性。在这里我是想介绍另外一种安全机制,即构建Remoting“防火墙”。
其实我所说的Remoting“防火墙”也是最基本的。由于Remoting的TcpChannel没有提供内建的认证机制,所以没有现成获取客户端的方法,我们可以在Remoting Server端注册上自定义的Server Channel Sink,通过Transport Headers来获取request的IP,以下是自定义的Server Channel Sink类的代码,(注:原代码不是我写的,原出处我忘记了,所以无法标注来源)
1using System;
2using System.Collections;
3using System.IO;
4using System.Runtime.Remoting;
5using System.Runtime.Remoting.Messaging;
6using System.Runtime.Remoting.Channels;
7using System.Threading;
8using System.Net;
9
10
11namespace Colorful.RemoteObject
12{
13 public class ClientIPServerSinkProvider : IServerChannelSinkProvider
14 {
15
16 private IServerChannelSinkProvider next = null;
17
18 public ClientIPServerSinkProvider()
19 {
20 }
21
22 public ClientIPServerSinkProvider(IDictionary properties, ICollection providerData)
23 {
24 }
25
26 public void GetChannelData(IChannelDataStore channelData)
27 {
28 }
29
30 public IServerChannelSink CreateSink(IChannelReceiver channel)
31 {
32 IServerChannelSink nextSink = null;
33
34 if (next != null)
35 {
36 nextSink = next.CreateSink(channel);
37 }
38
39 return new ClientIPServerSink(nextSink);
40 }
41
42
43
44 public IServerChannelSinkProvider Next
45 {
46 get { return next; }
47 set { next = value; }
48 }
49 }
50
51 public class ClientIPServerSink : BaseChannelObjectWithProperties, IServerChannelSink, IChannelSinkBase
52 {
53 private IServerChannelSink _next;
54
55 public ClientIPServerSink(IServerChannelSink next)
56 {
57 _next = next;
58 }
59
60 public void AsyncProcessResponse(System.Runtime.Remoting.Channels.IServerResponseChannelSinkStack sinkStack, System.Object state, System.Runtime.Remoting.Messaging.IMessage msg, System.Runtime.Remoting.Channels.ITransportHeaders headers, System.IO.Stream stream)
61 {
62 }
63
64 public Stream GetResponseStream(System.Runtime.Remoting.Channels.IServerResponseChannelSinkStack sinkStack, System.Object state, System.Runtime.Remoting.Messaging.IMessage msg, System.Runtime.Remoting.Channels.ITransportHeaders headers)
65 {
66 return null;
67 }
68
69 public System.Runtime.Remoting.Channels.ServerProcessing ProcessMessage(System.Runtime.Remoting.Channels.IServerChannelSinkStack sinkStack, System.Runtime.Remoting.Messaging.IMessage requestMsg, System.Runtime.Remoting.Channels.ITransportHeaders requestHeaders, System.IO.Stream requestStream, out System.Runtime.Remoting.Messaging.IMessage responseMsg, out System.Runtime.Remoting.Channels.ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
70 {
71 if (_next != null)
72 {
73 IPAddress ip = requestHeaders[CommonTransportKeys.IPAddress] as IPAddress;
74
75 CallContext.SetData("IP", ip);
76
77 ServerProcessing spres = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
78
79 return spres;
80 }
81 else
82 {
83 responseMsg = null;
84
85 responseHeaders = null;
86
87 responseStream = null;
88
89 return new ServerProcessing();
90 }
91 }
92
93
94
95 public IServerChannelSink NextChannelSink
96 {
97 get { return _next; }
98 set { _next = value; }
99 }
100 }
101}
102
以下是远程对象主程序代码
1class Program
2 {
3 static void Main(string[] args)
4 {
5 int TcpPort = ConfigInfo.RemoteSocketPort;
6 BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
7 provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
8 //实例化自定义的Server Channel Sink类
9 Colorful.RemoteObject.ClientIPServerSinkProvider IpInjProvider = new Colorful.RemoteObject.ClientIPServerSinkProvider();
10 provider.Next = IpInjProvider;//加入接收链
11
12 IDictionary props = new Hashtable();
13 props["port"] = TcpPort;
14
15 TcpChannel chan1 = new TcpChannel(props,null,provider);
16
17 ChannelServices.RegisterChannel(chan1, false);
18
19 LifetimeServices.LeaseTime = TimeSpan.Zero;//租用周期
20 RemotingConfiguration.RegisterWellKnownServiceType
21 (
22 typeof(Colorful.RemoteObject.Server),
23 ConfigInfo.RemoteSocketURI,
24 WellKnownObjectMode.Singleton
25 );
26 Console.WriteLine(DateTime.Now.ToString() + "服务通道注册成功!等待数据服务请求");
27
28 Console.ReadLine();
29 }
30 }
然后通过配置许可的IP地址XML文件,读取XML验证IP地址列表,然后调用以下函数验证客户端调用的合法性,非授权的IP拒绝访问
其实我所说的Remoting“防火墙”也是最基本的。由于Remoting的TcpChannel没有提供内建的认证机制,所以没有现成获取客户端的方法,我们可以在Remoting Server端注册上自定义的Server Channel Sink,通过Transport Headers来获取request的IP,以下是自定义的Server Channel Sink类的代码,(注:原代码不是我写的,原出处我忘记了,所以无法标注来源)
1using System;
2using System.Collections;
3using System.IO;
4using System.Runtime.Remoting;
5using System.Runtime.Remoting.Messaging;
6using System.Runtime.Remoting.Channels;
7using System.Threading;
8using System.Net;
9
10
11namespace Colorful.RemoteObject
12{
13 public class ClientIPServerSinkProvider : IServerChannelSinkProvider
14 {
15
16 private IServerChannelSinkProvider next = null;
17
18 public ClientIPServerSinkProvider()
19 {
20 }
21
22 public ClientIPServerSinkProvider(IDictionary properties, ICollection providerData)
23 {
24 }
25
26 public void GetChannelData(IChannelDataStore channelData)
27 {
28 }
29
30 public IServerChannelSink CreateSink(IChannelReceiver channel)
31 {
32 IServerChannelSink nextSink = null;
33
34 if (next != null)
35 {
36 nextSink = next.CreateSink(channel);
37 }
38
39 return new ClientIPServerSink(nextSink);
40 }
41
42
43
44 public IServerChannelSinkProvider Next
45 {
46 get { return next; }
47 set { next = value; }
48 }
49 }
50
51 public class ClientIPServerSink : BaseChannelObjectWithProperties, IServerChannelSink, IChannelSinkBase
52 {
53 private IServerChannelSink _next;
54
55 public ClientIPServerSink(IServerChannelSink next)
56 {
57 _next = next;
58 }
59
60 public void AsyncProcessResponse(System.Runtime.Remoting.Channels.IServerResponseChannelSinkStack sinkStack, System.Object state, System.Runtime.Remoting.Messaging.IMessage msg, System.Runtime.Remoting.Channels.ITransportHeaders headers, System.IO.Stream stream)
61 {
62 }
63
64 public Stream GetResponseStream(System.Runtime.Remoting.Channels.IServerResponseChannelSinkStack sinkStack, System.Object state, System.Runtime.Remoting.Messaging.IMessage msg, System.Runtime.Remoting.Channels.ITransportHeaders headers)
65 {
66 return null;
67 }
68
69 public System.Runtime.Remoting.Channels.ServerProcessing ProcessMessage(System.Runtime.Remoting.Channels.IServerChannelSinkStack sinkStack, System.Runtime.Remoting.Messaging.IMessage requestMsg, System.Runtime.Remoting.Channels.ITransportHeaders requestHeaders, System.IO.Stream requestStream, out System.Runtime.Remoting.Messaging.IMessage responseMsg, out System.Runtime.Remoting.Channels.ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
70 {
71 if (_next != null)
72 {
73 IPAddress ip = requestHeaders[CommonTransportKeys.IPAddress] as IPAddress;
74
75 CallContext.SetData("IP", ip);
76
77 ServerProcessing spres = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
78
79 return spres;
80 }
81 else
82 {
83 responseMsg = null;
84
85 responseHeaders = null;
86
87 responseStream = null;
88
89 return new ServerProcessing();
90 }
91 }
92
93
94
95 public IServerChannelSink NextChannelSink
96 {
97 get { return _next; }
98 set { _next = value; }
99 }
100 }
101}
102
1class Program
2 {
3 static void Main(string[] args)
4 {
5 int TcpPort = ConfigInfo.RemoteSocketPort;
6 BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
7 provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
8 //实例化自定义的Server Channel Sink类
9 Colorful.RemoteObject.ClientIPServerSinkProvider IpInjProvider = new Colorful.RemoteObject.ClientIPServerSinkProvider();
10 provider.Next = IpInjProvider;//加入接收链
11
12 IDictionary props = new Hashtable();
13 props["port"] = TcpPort;
14
15 TcpChannel chan1 = new TcpChannel(props,null,provider);
16
17 ChannelServices.RegisterChannel(chan1, false);
18
19 LifetimeServices.LeaseTime = TimeSpan.Zero;//租用周期
20 RemotingConfiguration.RegisterWellKnownServiceType
21 (
22 typeof(Colorful.RemoteObject.Server),
23 ConfigInfo.RemoteSocketURI,
24 WellKnownObjectMode.Singleton
25 );
26 Console.WriteLine(DateTime.Now.ToString() + "服务通道注册成功!等待数据服务请求");
27
28 Console.ReadLine();
29 }
30 }
验证客服端的合法性#region 验证客服端的合法性
/**//// <summary>
/// 检查Remoting客户端的合法性
/// </summary>
/// <returns></returns>
public bool CheckRemotingClient()
{
IPAddress data = (IPAddress)CallContext.GetData("ClientIPAddress");
if (clientIPAddress.ContainsKey(data))
{
string msg = "接受远程地址:" + data.ToString() + "的服务请求";
Console.WriteLine(msg);
return true;
}
else
{
string msg = "远程地址:" + data.ToString() +"不在许可范围内,服务请求被拒绝";
Console.WriteLine(msg);
SQL2005DAL.CommDAL.WriteLogFile("RemotingClientTrace", msg, "Warring", false);
return false;
}
}
#endregion
基本上就这么多,详细内容,请参看VB.NET Remoting技术手册,其他安全请参看.NET Remoting 安全性/**//// <summary>
/// 检查Remoting客户端的合法性
/// </summary>
/// <returns></returns>
public bool CheckRemotingClient()
{
IPAddress data = (IPAddress)CallContext.GetData("ClientIPAddress");
if (clientIPAddress.ContainsKey(data))
{
string msg = "接受远程地址:" + data.ToString() + "的服务请求";
Console.WriteLine(msg);
return true;
}
else
{
string msg = "远程地址:" + data.ToString() +"不在许可范围内,服务请求被拒绝";
Console.WriteLine(msg);
SQL2005DAL.CommDAL.WriteLogFile("RemotingClientTrace", msg, "Warring", false);
return false;
}
}
#endregion