Socket开发框架之数据加密及完整性检查

在前面两篇介绍了Socket框架的设计思路以及数据传输方面的内容,整个框架的设计指导原则就是易于使用及安全性较好,可以用来从客户端到服务端的数据安全传输,那么实现这个目标就需要设计好消息的传输和数据加密的处理。本篇主要介绍如何利用Socket传输协议来实现数据加密和数据完整性校验的处理,数据加密我们可以采用基于RSA非对称加密的方式来实现,数据的完整性,我们可以对传输的内容进行MD5数据的校验对比。

1、Socket框架传输内容分析

前面介绍过Socket的协议,除了起止标识符外,整个内容是一个JSON的字符串内容,这种格式如下所示。

上述消息内容,我们可以通过开始标识位和结束标识位,抽取出一个完整的Socket消息,这样我们对其中的JSON内容进行序列号就可以得到对应的实体类,我们定义实体类的内容如下所示。

我们把消息对象分为请求消息对象和应答消息对象,他们对应的是Request和Response的消息,也就是一个是发起的消息,一个是应答的消息。其中上图的“承载的JSON内容就是我们另一个传输对象的JSON字符串,这样我们通过这种字符串来传输不同对象的信息,就构造出了一个通用的消息实体对象。

另外这些传输的消息对象,它本身可以继承于一个实体类的基类,这样方便我们对它们的统一处理,如下图所示,就是一个通用的消息对象BaseMessage和其中JSON内容的对象关系图,如AuthRequest是登陆验证请求,AuthorRepsonse是登陆验证的应答。

当然,我们整个Socket应用,可以派生出很多类似的Request和Response的消息对象,如下所示是部分消息的定义。

对于非对称加密的处理,一般来说会有一些性能上的损失,不过我们考虑到如果是安全环境的数据传输处理的话,我们使用非对称加密还是比较好的。

当然也有人建议采用非对称加密部分内容,如双方采用约定的对称加密键,通过非对称加密的方式来传输这个加密键,然后两边采用对称加密算法来处理也是可以的。不过本框架主要介绍采用非对称加密的方式来加密其中的JSON内容,其他部分常规的信息不进行加密。

2、非对称加密的公钥传递

消息加密数据的传输前,我们需要交换算法的公钥,也就是服务器把自己公钥给客户端,客户端收到服务器的公钥请求后,返回客户端的公钥给服务器,实现两者的交换,以后双方的消息都通过对方公钥加密,把加密内容通过标准的Socket消息对象传递,这样对方收到的加密内容,就可以通过自身的私钥进行解密了。

那么要在传递消息前处理这个公钥交换的话,我们可以设计在服务器接入一个新的客户端连接后(在登录处理前),向客户端发送服务器的公钥,客户端受到服务器的公钥后,回应自己的公钥信息,并存储服务器的公钥。这样我们就可以在登陆的时候以及后面的消息传递过程中,使用对方公钥进行加密数据,实现较好的安全性。

公钥传递的过程如下图所示,也就是客户端发起连接服务器请求后,由服务器主动发送一个公钥请求命令,客户端收到后进行响应,发送自身的公钥给服务器,服务器把客户端的公钥信息存储在对应的Socket对象上,以后所有消息都通过客户端公钥加密,然后发送给客户端。

前面我们介绍过,我们所有的自定义Socket对象,都是继承于一个BaseSocketClient这样的基类对象,那么我们只需要在它的对象里面增加几个属性几个,一个是自己的公钥、私钥,一个是对方的公钥信息,如下所示。

在程序的启动后,包括客户端启动,服务器启动,我们都需要构建好自己的公钥私钥信息,如下代码是产生对应的公钥私钥信息,并存储在属性里面。

            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                this.RSAPublicKey = rsa.ToXmlString(false);// 公钥
                this.RSAPrivateKey = rsa.ToXmlString(true);// 私钥
            }

例如在服务器端,在客户端Socket成功接入后,我们就给对应的客户端发送公钥请求消息,如下代码所示。

        /// <summary>
        /// 客户端连接后的处理(如发送公钥秘钥)
        /// </summary>
        /// <param name="client">连接客户端</param>
        protected override void OnAfterClientConnected(ClientOfShop client)
        {
            //先记录服务端的公钥,私钥
            client.RSAPrivateKey = Portal.gc.RSAPrivateKey;
            client.RSAPublicKey = Portal.gc.RSAPublicKey;

            //发送一个公钥交换命令
            var request = new RsaKeyRequest(Portal.gc.RSAPublicKey);
            var data = request.PackData();
            client.SendData(data);
            Thread.Sleep(100);
        }

那么在客户端,接收到服务端的消息后,对消息类型判断,如果是公钥请求,那么我们需要进行回应,把自己的公钥发给服务器,否则就进行其他的业务处理了。

        /// <summary>
        /// 重写读取消息的处理
        /// </summary>
        /// <param name="message">获取到的完整Socket消息对象</param>
        protected override void OnMessageReceived(BaseMessage message)
        {
            if (message.MsgType == DataTypeKey.RSARequest)
            {
                var info = JsonTools.DeserializeObject<RsaKeyRequest>(message.Content);
                if (info != null)
                {
                    //记录对方的公钥到Socket对象里面
                    this.PeerRSAPublicKey = Portal.gc.UseRSAEncrypt ? info.RSAPublicKey : "";
                    Console.WriteLine("使用RAS加密:{0},获取到加密公钥为:{1}", Portal.gc.UseRSAEncrypt, info.RSAPublicKey);

                    //公钥请求应答
                    var publicKey = Portal.gc.UseRSAEncrypt ? Portal.gc.RSAPublicKey : "";
                    var data = new RsaKeyResponse(publicKey);//返回客户端的公钥
                    var msg = data.PackData(message);

                    SendData(msg);
                    Thread.Sleep(100);//暂停下
                }
            }
            else
            {
                //交给业务消息处理过程
                this.MessageReceiver.AppendMessage(message);
                this.MessageReceiver.Check();
            }
        }

如果我们交换成功后,我们后续的消息,就可以通过RSA非对称加密进行处理了,如下代码所示。

data.Content = RSASecurityHelper.RSAEncrypt(this.PeerRSAPublicKey, data.Content);

而解密消息,则是上面代码的逆过程,如下所示。

message.Content = RSASecurityHelper.RSADecrypt(this.RSAPrivateKey, message.Content);

最后我们把加密后的内容组成一个待发送的Socket消息,包含起止标识符,如下所示。

                //转为JSON,并组装为发送协议格式
                var json = JsonTools.ObjectToJson(data);
                toSendData = string.Format("{0}{1}{2}", (char)this.StartByte, json, (char)this.EndByte);

这样就是我们需要发送的消息内容了,我们拦截内容,可以看到大概的内容如下所示。

上面红色框的内容,必须使用原有的私钥才能进行解密,也就是在网络上,被谁拦截了,也无法进行解开,保证了数据的安全性。

3、数据完整性检查

 数据的完整性,我们可以通过消息内容的MD5值进行比对,实现检查是否内容被篡改过,不过如果是采用了非对称加密,这种 完整性检查也可以忽略,不过我们可以保留它作为一个检查处理。

因此在封装数据的时候,就把内容部分MD5值计算出来,如下所示。

data.MD5 = MD5Util.GetMD5_32(data.Content);//获取内容的MD5值

然后在获得消息,并进行解密后(如果有),那么在服务器端计算一下MD5值,并和传递过来的MD5值进行比对,如果一致则说明没有被篡改过,如下代码所示。

                var md5 = MD5Util.GetMD5_32(message.Content);
                if (md5 == message.MD5)
                {
                    OnMessageReceived(message);//给子类重载
                }
                else
                {
                    Log.WriteInfo(string.Format("收到一个被修改过的消息:\r\n{0}", message.Content));
                }

以上就是我在Socket开发框架里面,实现传输数据的非对称加密,以及数据完整性校验的处理过程。

本文转自博客园伍华聪的博客,原文链接:Socket开发框架之数据加密及完整性检查,如需转载请自行联系原博主。

时间: 2024-08-03 08:34:58

Socket开发框架之数据加密及完整性检查的相关文章

SuperSocket v1.3发布 轻量级可扩展的Socket开发框架

SuperSocket 是一个轻量级的可扩展的 Socket http://www.aliyun.com/zixun/aggregation/13435.html">开发框架,可用来构建一个基于命令的服务器端 Socket 程序,而无需了解如何使用 Socket,如何维护Socket连接,Socket是如何工作的.该项目使用纯 C# 开发,易于扩展和集成到已有的项目.只要你的已有系统(forum/CRM/MIS/HRM/ERP)是使用.NET开发的,你都能够使用 SuperSocket来轻

Socket开发框架之框架设计及分析

虽然在APP应用.Web应用.Winform应用等大趋势下,越来越多的企业趋向于这些应用系统开发,但是Socket的应用在某些场合是很必要的,如一些停车场终端设备的接入,农业或者水利.压力监测方面的设备数据采集等,以及常见的IM(即时通讯,如腾讯QQ.阿里旺旺等)的客户端,都可以采用Socket框架进行相关的数据采集和信息通讯用途的,Socket应用可以做为APP应用.Web应用和Winform应用的补充. 1.Socket应用场景 一般情况下,客户端和服务端进行Socket连接,需要进行数据的

Socket开发框架之数据传输协议

我在前面一篇随笔<Socket开发框架之框架设计及分析>中,介绍了整个Socket开发框架的总体思路,对各个层次的基类进行了一些总结和抽象,已达到重用.简化代码的目的.本篇继续分析其中重要的协议设计部分,对其中消息协议的设计,以及数据的拆包和封包进行了相关的介绍,使得我们在更高级别上更好利用Socket的特性. 1.协议设计思路 对Socket传输消息的封装和拆包,一般的Socket应用,多数采用基于顺序位置和字节长度的方式来确定相关的内容,这样的处理方式可以很好减少数据大小,但是这些处理对我

Socket开发框架之消息的回调处理

在一般的Socket应用里面,很多时候数据的发送和接收是分开处理的,也就是我们发送一个消息,不知道这个请求消息什么时候得到应答消息,而且收到对应的应答消息的时候,如果操作界面的内容,也是需要特别处理的,因为它们和界面线程是不在一起的.如果我们在发送消息的时候,能够给一段回调的代码给收到应答消息的时候处理,那么就会方便很多.本文主要介绍如何在Socket应用里面,通过回调函数的处理,实现收到应答消息的时候能够调用对应的函数. 1.回调函数的设计 在上一篇的随笔里面,介绍了基于Json的Socket

Socket开发框架之数据采集客户端

虽然目前.NET的主流的开发基本上是基于Web方式(传统的Web方式和Silvelight方式).基于Winform方式(传统的Winform模式和WPF方式等).基于服务应用方式(传统的WebService和WCF服务方式)等主要几种开发,另外,还有一种就是基于Socket协议的开发方式,不同于高级服务层的WebService和WCF服务,基于Socket协议开发是较为底层的开发方式,它往往具有更加灵活,可控性更高的优点,不过相对来说,开发难度也会大一些. 我由于工作需要,需要开发一个数据采集

SuperSocket v1.4 beta 2发布 可扩展的Socket开发框架

SuperSocket 是一个轻量级的可扩展的 Socket http://www.aliyun.com/zixun/aggregation/13435.html">开发框架,可用来构建一个服务器端 Socket 程序,而无需了解如何使用 Socket,如何维护Socket连接,Socket是如何工作的.该项目使用纯 C# 开发,易于扩展和集成到已有的项目.只要你的已有系统(forum/CRM/MIS/HRM/ERP)是使用.NET开发的,你都能够使用 SuperSocket来轻易的开发出

这些开源项目,你都知道吗?(持续更新中...)[原创]

原文 这些开源项目,你都知道吗?(持续更新中...)[原创] Json.NET  http://json.codeplex.com/ Json.Net是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单.通过Linq To JSON可以快速的读写Json,通过JsonSerializer可以序列化你的.Net对象.让你轻松实现.Net中所有类型(对象,基本数据类型等)和Json的转换.   Math.NET http://www.mathdotn

.net开源框架开源类库(整理)

源:http://www.cnblogs.com/chinanetwind/p/3715809.html 常用库 Json.NET  https://github.com/JamesNK/Newtonsoft.Json Json.Net 是一个读写Json效率比较高的.Net框架.Json.Net 使得在.Net环境下使用Json更加简单.通过Linq To JSON可以快速的读写Json,通过JsonSerializer可以序列化你的.Net对象.让你轻松实现.Net中所有类型(对象,基本数据

2014年,年度最热中国开源软件TOP100你知道多少?

不知道从什么时候开始,很多一说起国产好像就非常愤慨,其实大可不必.做开源中国六年有余,这六年时间国内的开源蓬勃发展,从一开始的使用到贡献,到推出自己很多的开源软件,而且还有很多软件被国外的认可.中国是开源不可忽视的力量. 而我们这个榜单也是从这些国人开发.主要参与开发或者基于国外开源软件进行改进并形成独立版本的软件中,根据该软件的访问.收藏.下载等多个角度, 从而得出前 100 名最受欢迎的开源软件.我们所评选出来的软件并非同类型,尽管放在一起不是很科学,但我们仍希望通过我们的视角让大家对国内一