在分布式通信系统中,安全无疑是非常重要的。ESFramework通信框架提供了哪些安全保障了?由于ESFramework通信框架是应用层的开发框架,那么本文我们只讨论ESFramework通信框架在应用层涉及到的安全问题。如果黑客是在网络层或链路层进行攻击,位于应用层的系统是无能为力的。从应用层来说,安全的重要性主要体现在以下几个方面:
(1) 防止恶意用户使用格式不正确的消息来试探服务端。
(2) 防止通信的消息被恶意用户截获,或者,即使被恶意用户截获,也无法破解其内容。
(3) 防止恶意用户在未成功登录前,就向服务器发送格式正确的伪装消息。
(4) 防止恶意用户使用巨大数量的空连接来消耗服务器的资源。

ESFramework通信框架内置了一些安全机制,以对上述的安全性提供一些保障,下面我们一一说明。

1.消息格式验证

ESFramework通信框架定义了通信消息的总体格式(即消息必须由消息头Header和消息体Body构成),而为了支持快速开发,ESPlus则定义了消息的详细格式(如StreamMessageHeader、TextMessageHeader等)。

当网络引擎(无论是服务端的还是客户端的)从网络上接收到一批二进制数据时,会尝试去解析它。如果解析时发现,这批二进制数据的格式不是我们预定义好的消息的格式时,将会认为其是非法消息。此时,网络引擎将会丢弃非法数据,并关闭对应的连接(如果引擎是基于TCP协议的),然后再触发INetEngine接口的InvalidMessageReceived事件。

  /// <summary>
/// 当接收到不完整或无法解析的数据时触发该事件
/// </summary>
event CbGeneric<UserAddress, MessageInvalidType> InvalidMessageReceived;

事件的参数UserAddress说明了非法消息来源于哪个用户地址;而MessageInvalidType参数则说明了非法消息的类型:

    /// <summary>
/// 接收到的无效的消息分类。
/// </summary>
public enum MessageInvalidType
{
/// <summary>
/// 正常消息。
/// </summary>
Valid = 0,
/// <summary>
/// 消息尺寸溢出。
/// </summary>
MessageSizeOverflow,
/// <summary>
/// 无效的消息头
/// </summary>
InvalidHeader,
/// <summary>
/// 无效的标识符
/// </summary>
InvalidToken,
/// <summary>
/// 数据包长度不够
/// </summary>
DataLacked,
/// <summary>
/// 无效的客户端类型
/// </summary>
InvalidClientType
}

从该枚举可以看出,网络引擎收到的数据无法解析的愿意有几种:消息尺寸超过规定的大小,消息头无效、消息的标识符无效等。

2.消息加密

对于一些关键的信息,是绝对不允许以明文的形式在网络上进行传送的。所以,消息在发送之前,必须进行加密。

如果直接基于ESFramework通信框架开发(不使用ESPlus),那么,熟悉ESFramework通信框架骨架流程的朋友都知道IMessageTransformer接口,我们可以将其实现类的实例挂接在骨架流程的对应位置,以对进出的消息进行变形处理。所以,我们可以在IMessageTransformer的实现类中,完成对消息的加密和解密动作,比如,像这样:

    public class MessageEncryptor : IMessageTransformer
{
public IMessage CaptureBeforeSendMessage(IMessage msg)
{
//加密消息
return Encrypt(msg);
} public IMessage CaptureReceivedMessage(IMessage msg)
{
//解密消息
return Decrypt(msg);
}
}

如果使用的是ESPlus提供的Rapid引擎,由于Rapid内部在组装骨架流程时,是没有使用加密组件的,所以不能使用IMessageTransformer接口。但是,我们仍然可以在发送自定义信息时,保证信息的安全。我们是使用ICustomizeOutter发送自定义信息的,以Send方法为例:

  /// <summary>
/// 向服务器发送信息。
/// </summary>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">信息</param>
void Send(int informationType, byte[] info);

在调用Send方法之前,我们可以先将要发送的内容info进行加密,然后再发送加密后的结果。
      而在接收方,会调用ICustomizeHandler的HandleInformation方法来处理接收到的信息:

  /// <summary>
/// 处理来自客户端的自定义信息。
/// </summary>
/// <param name="sourceUserID">发送该信息的用户ID</param>
/// <param name="informationType">自定义信息类型</param>
/// <param name="info">信息</param>
void HandleInformation(string sourceUserID, int informationType, byte[] info);

在实现HandleInformation方法时,我们可以先解密info,然后再进行正常的业务处理。

无论是挂接IMessageTransformer组件,还是在发送或接收自定义信息时,手动加解密信息,都要注意一点,那就是加解密都是要消耗CPU和内存资源的,对于那些高频通信的消息来说,这个开销是绝不可忽视的。所以,我们应该尽可能的只加密那些极其重要的消息/信息(根据MessageType或InfomationType来进行区分),而不是将所有的消息/信息一视同仁。

3.验证第一个消息

有的恶意用户,在破解了消息的格式之后,会尝试在不登录的情况下,向服务器发送其他类型的请求消息。ESFramework通信框架支持在服务端对每个连接上收到的第一个消息进行验证,如果验证通不过,则将关闭对应的连接。验证第一个消息的组件的接口是IFirstMessageVerifier:

    public interface IFirstMessageVerifier
{
/// <summary>
// 当每个TCP连接建立成功后,将会验证从该连接上接收到的第一个消息。如果通不过验证,服务端TCP引擎将会关闭对应的连接。
/// </summary>
/// <param name="firstMessage">TCP连接上的第一个消息</param>
/// <param name="address">TCP连接的客户端地址</param>
/// <returns>验证是否通过</returns>
bool VerifyFirstMessage(UserAddress address , IMessage firstMessage);
}

我们可以实现这个接口,并将其注入到ITcpServerEngine对应的属性上。当VerifyFirstMessage方法返回false时,表示验证失败,此时,服务端网络引擎将会关闭对应的TCP连接。

如果我们使用的是ESPlus提供的Rapid引擎,Rapid引擎内部已经实现了IFirstMessageVerifier接口来为我们验证第一个消息,它主要是保证第一个消息必须是Logon消息,再结合前面介绍的登陆账号密码验证,就可以解决恶意用户在未登录的情况下,就进行其它类型的业务请求的情况出现。

4.绑定连接(Session)

当Logon消息中的帐号密码通过服务端的验证之后,服务端会将该帐号与对应的TCP连接绑定起来,构成一个完整的Session。如果该连接上接收到的后续消息中,只要发现消息头中的UserID与该TCP连接绑定的帐号不一致,则认为该消息为非法消息,此时,服务端网络引擎将会关闭对应的TCP连接。如此,可以防止用一个帐号登录成功后,再用另一个帐号来请求服务。

5.空连接

到这里,我们已经解决了本文开始提出的前三个问题,这就保证了恶意用户无法向服务器发送恶意的消息了。但是,恶意用户在应用层还可以做一件事情,就是消耗服务端的TCP连接。对于每个已成功建立的TCP连接,服务端都要为其分配一定的资源并对其进行管理。如果恶意的用户和服务器之间建立很多空闲的连接,对服务器资源的消耗也是不可忽视的。

ESFramework通信框架提供的服务端引擎ITcpServerEngine支持及时地关闭上述的恶意用户的空闲连接。ITcpServerEngine有一个ExpiredSpanInSecs属性,该属性的含义是:某个TCP连接连上后,如果在ExpiredSpanInSecs时间内服务端网络引擎都接收不到来自该连接的任何数据,则将关闭该连接。

一般正常的TCP连接建立成功后,客户端会立即向服务器发送Logon消息进行登录。所以,这个机制是可以成立的。我们可以将ExpiredSpanInSecs设为一个有效值(如3s),来减轻空连接的影响。之所以说是“减轻”,而不是“消除”,是因为在应用层系统中,无法完全规避这个问题,就按照3秒钟的超时来说,你服务端关闭连接的速度一定赶不上恶意用户建立连接的速度。

解决这个问题的更好办法,应该是在防火墙上做相关的策略设定,比如屏蔽掉恶意用户的IP地址,过滤由该地址发出TCP握手请求的Syn包,等等。

ESFramework 通信框架安全机制的设计与实现的更多相关文章

  1. 可靠通信的保障 —— 使用ACK机制发送自定义信息——ESFramework 通信框架4.0 快速上手(12)

    使用ESPlus.Application.CustomizeInfo.Passive.ICustomizeInfoOutter接口的Send方法,我们已经可以给服务端或其它在线客户端发送自定义信息了, ...

  2. 文件断点续传原理与实现—— ESFramework 通信框架4.0 进阶(12)

    在ESFramework通信框架 4.0 快速上手(13) -- 文件传送,如此简单一文的详细介绍和ESFramework通信框架 4.0 快速上手(14) -- 聊天系统Demo,增加文件传送功能( ...

  3. 成熟的C#网络通信框架介绍——ESFramework通信框架

    (转自:http://www.cnblogs.com/zhuweisky/archive/2010/08/12/1798211.html) ESFramework通信框架是一套性能卓越.稳定可靠.强大 ...

  4. ESPlatform 支持的三种群集模型 —— ESFramework通信框架 4.0 进阶(09)

    对于最多几千人同时在线的通信应用,通常使用单台服务器就可以支撑.但是,当同时在线的用户数达到几万.几十万.甚至百万的时候,我们就需要很多的服务器来分担负载.但是,依据什么规则和结构来组织这些服务器,并 ...

  5. 基于Java Mina 通信框架的JT/T809转发服务器设计

    Apache MINA 是 Apache 组织的一个开源项目,为开发高性能和高可用性的网络应用程序提供了非常便利的框架. 也是Java开发者的一个福利(.NET目前还没有类似封装的这么好的基础sock ...

  6. MEF插件系统中通信机制的设计和实现

    MEF插件系统中通信机制的设计和实现 1.背景 一般的WinForm中通过C#自带的Event机制便能很好的实现事件的注册和分发,但是,在插件系统中却不能这么简单的直接用已有的类来完成.一个插件本不包 ...

  7. 基于Java Mina 和Netty 通信框架的JT/T809转发服务器设计

    Apache MINA 是 Apache 组织的一个开源项目,为开发高性能和高可用性的网络应用程序提供了非常便利的框架. 也是Java开发者的一个福利(.NET目前还没有类似封装的这么好的基础sock ...

  8. 高性能 TCP & UDP 通信框架 HP-Socket v3.3.1

    HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...

  9. 高性能 TCP & UDP 通信框架 HP-Socket v3.2.3

    HP-Socket 是一套通用的高性能 TCP/UDP 通信框架,包含服务端组件.客户端组件和 Agent 组件,广泛适用于各种不同应用场景的 TCP/UDP 通信系统,提供 C/C++.C#.Del ...

随机推荐

  1. quagga源码分析--通用库thread

    quagga是开源路由器软件,提供的用户界面与思科,华为的路由器的人机接口几乎一致,非常有学习价值,尤其是开源的协议代码,简直亮瞎了我的小眼睛. quagga的介绍,我就不赘述了,有兴趣的可以找度娘或 ...

  2. CodeForces 706D Vasiliy's Multiset

    字典树. 比较经典的题目了.把每一个数字都插入到字典树中,询问的时候如果$x$的第$i$位是$p$,那么尝试着在字典树上往$pXOR1$的节点走下去,没有$pXOR1$节点的话再走$p$的.删除操作的 ...

  3. 注意Thread.interrupt()方法的真正作用并不是用来中断线程

      程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的.难以发现的错误.      在本篇文章中,我们针对这些难题之一:如何中断一个正在 ...

  4. Linq 内联左联等

    我们在做SQL查询的时候经常会用到Inner Join,Left Join,笛卡尔积等等,连接方式的概念方面我想也不用给予太多解释, 我们今天的重点是让大家熟悉LINQ是如何使用Join来实现常用的表 ...

  5. Mysql的热备份[转载]

    学一点 mysql 双机异地热备份----快速理解mysql主从,主主备份原理及实践 双机热备的概念简单说一下,就是要保持两个数据库的状态自动同步.对任何一个数据库的操作都自动应用到另外一个数据库,始 ...

  6. Ecstore安装篇-2.单机部署【linux】

    单机部署实施-linux 单机部署实施-linux author :James,jimingsong@vip.qq.com since :2015-03-02 系统环境需求 软件来源 底层依赖 1. ...

  7. 删除和创建ms sql的分区文件

    今天测试ms sql 的表分区的时候,不小心搞错了分区的条件.然后我想重新做一次,操作流程如下(按顺序) 1:删除SCHEME DROP  PARTITION SCHEME TestSPScheme ...

  8. svn is already locked解决办法

    在出错文件夹下,鼠标右键

  9. HDU 5572 An Easy Physics Problem (计算几何+对称点模板)

    HDU 5572 An Easy Physics Problem (计算几何) 题目链接http://acm.hdu.edu.cn/showproblem.php?pid=5572 Descripti ...

  10. 读取和存储文本文件,UTF-8和GB2312通用的函数

    '------------------------------------------------- '函数名称:ReadTextFile '作用:利用AdoDb.Stream对象来读取UTF-8格式 ...