如何检测非法包,哈希校验如何实现

yaopeijiang7 2013-12-19 04:07:27


void main()
{

for(;cpu*2+2;)///启动cpu*2+2个工作线程去处理异步消息
{
Thread(NULL,NULL,Workthread,this,NULL);
}

for(;10;)
{
PostAccept(); /////投递10个异步Accept请求
}

}

Workthread()
{
while()
{
if(GetMeaage()!=true);//循环接收异步消息
continue;
CheckEeror(); ///检查错误码
switch(Type)
{
case Accept: //收到连接消息
{
Getinfo(); //获取远程主机信息
PostWsaRecv(Head);////投递异步接收包头请求
PostAccept(); ///继续投递异步Accept请求,保持工作线程能同时接收10个连接
}

case Head: //收到包头消息
{
SetMsg();把提取包头的数据加入到消息结构体中
PostWsaRecv(Body);//投递异步接收包体消息
}
break;

case Body: ///收到包体消息
{
if(Bodylent < HeadMsg.lent)///收到的包体是殘包,有可能这是个非法包,又有可能数据还在缓冲区里面
{

//////////////////////////////////////////////////////////////如果数据还在缓冲区里面那就继续接收就可以了
SetMsg(); //重新设置消息结构体内容

PostWsaRecv(Body);//投递异步接收包体消息
//////////////////////////////////////////////////////////////////////////////////////////////////


但是,如果是黑客发送过来的一个非法包呢?

/*
实际期待: 01 08 00 00 00 00 00 00 00 00
黑客发送一个比包头要小的数据包:01 08 00 00 00 00 00 00 00


就会造成工作线程死锁,当黑客发送几十个这样的包时候你的程序也就挂掉了

老师说收到殘包之后进行哈希校验

百度了一下哈希校验还不是很懂,这里希望大家能帮忙解决下


if(Hashchek == 非法包)
{
closesoket();
}
*/

}

else if(Bodylent > HeadMsg.lent)//收到的包体大小大于包头定义的大小说明是非法包,直接断开连接
{
closesoket();
}
else if(Body == HeadMsg.lent) ///包体收完了
{
PostWsaRecv(Head);//投递异步接收包头消息用来接收下一次数据包的收发
}
else ///奇葩的长度,直接断开你
{
closesoket();
}
}
case send:
{
PostWsaSend(); //投递异步发送消息
}
break;
}
}
}



这是小弟写的一个完成端口模型,为了方面上的是伪代码,code在这了,大家帮忙看下,问题描述在注视上面

...全文
1634 8 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
zilaishuichina 2013-12-19
  • 打赏
  • 举报
回复
引用 7 楼 yaopeijiang7 的回复:
GetQueuedCompletionStatus的第二个参数可获取到每次接收到的数据包实际长度,遇到残包时加入结构体进行统计
如果你这个Bodylent是GetQueuedCompletionStatus的第二个参数统计出来的 那么 分两种情况 1,你在WSARECV的时候 没有指定想获取多长的数据,而是按照buf的最大长度有多少获取多少 那么 即使是正常的包 你一样有可能 会出现Bodylent > HeadMsg.lent 此时这个条件不能判断是否是非法包 因为你发送端 发两次数据 一次是 01 02 03 04 第二次是 05 06 07 08 你接收端可能第一次接收到的是 01 02 03 04 05 06 第二次是 07 08 2,你在WSARECV的时候 你指定了希望能获取到多长的数据,那么此时你希望能获取到的数据长度是根据 HeadMsg.lent - Bodylent 算出来的 那么 Bodylent只会小于等于HeadMsg.lent 不会大于HeadMsg.lent
yaopeijiang7 2013-12-19
  • 打赏
  • 举报
回复
引用 4 楼 zilaishuichina 的回复:
这个包体的长度 实际上我之前做的时候 是做了一个上限的限制的 比如 我会规定 一个逻辑包最大不超过10K (如果逻辑确实有大数据要发送,逻辑可以自己拆分小包,到了接收端再到逻辑层自己组合) 在读取包头的数据的时候 如果 解出的长度不正确 直接就踢掉该连接 不会再继续下去 所以不用担心产生你所说的工作线程死锁 你就按照你自己的规定好的格式去解就可以了 例如 我的包头里面 有4个字节表示长度 一个正常的包 (比如一个1K的包) 应该是 00 04 00 00 后面跟着1K的数据 如果说 收到的一个非法包 它少一个字节 00 04 00 我还是等凑足4个字节才去解析 那么后面凑上来的这一个字节 可能就是其他值 导致这个本应是包头的4字节变成了比如00 04 00 01 那么这个长度解出来就是远大于10K的一个值 那么显然就是一个非法包 如果说后面凑上来的这一个字节 恰好是 00 解出来包体长度1K 那么就按照正常包处理 继续读取1k的数据 当然由于这个包数据时错位的 那么这个包在解出来之后 交给逻辑层 逻辑层会发现包体里面的数据是乱的 逻辑层自己去处理错误的包 由于这个包错位了一个字节 那么在这个包之后 后面的每一个包肯定都是错的 那么后面肯定能有一个包在解包头的时候 长度不正确 然后将其踢掉 (或者逻辑层已经先一步踢掉这个连接了) 同理 如果是包体少一个字节 最终也会导致解下一个包头出错 然后 在你的这个伪代码里面 我觉得其实有点理想化了 因为 你一开始是无法确定你的这个 case Body: 中的 Bodylent 你能确定的只有HeadMsg.lent 你在收到case Head的时候 应该是根据这个HeadMsg.lent去PostWsaRecv(Body); 收足HeadMsg.lent才会返回 开始解包体 如果还没有凑足HeadMsg.lent 应该是继续PostWsaRecv(Body)直到凑足HeadMsg.lent为止
GetQueuedCompletionStatus的第二个参数可获取到每次接收到的数据包实际长度,遇到残包时加入结构体进行统计
yaopeijiang7 2013-12-19
  • 打赏
  • 举报
回复
else if(Bodylent > HeadMsg.lent) 黑客定义的非法包 01 03 00 00 00 00 00类似于这样的
zilaishuichina 2013-12-19
  • 打赏
  • 举报
回复
else if(Bodylent > HeadMsg.lent) 如果你是按照 HeadMsg.lent去PostWsaRecv(Body) 那么是不会进入这个分支的 所以实际代码可能应该是这样

case Head:      
{
    ProcessHead();
    CheckHead();
    PostWsaRecv(Body);
}
break;
case Body:
{
    if(Bodylent < HeadMsg.lent)
    {   
        PostWsaRecv(Body);
        //这里不需要考虑是包的内容长度是否够
        //只要还有数据过来 你总是能凑够HeadMsg.lent
        //如果一直没有数据过来 就是超时处理
    }
    else
    {
        ProcessBody();
        PostWsaRecv(Head);
    }
}
zilaishuichina 2013-12-19
  • 打赏
  • 举报
回复
这个包体的长度 实际上我之前做的时候 是做了一个上限的限制的 比如 我会规定 一个逻辑包最大不超过10K (如果逻辑确实有大数据要发送,逻辑可以自己拆分小包,到了接收端再到逻辑层自己组合) 在读取包头的数据的时候 如果 解出的长度不正确 直接就踢掉该连接 不会再继续下去 所以不用担心产生你所说的工作线程死锁 你就按照你自己的规定好的格式去解就可以了 例如 我的包头里面 有4个字节表示长度 一个正常的包 (比如一个1K的包) 应该是 00 04 00 00 后面跟着1K的数据 如果说 收到的一个非法包 它少一个字节 00 04 00 我还是等凑足4个字节才去解析 那么后面凑上来的这一个字节 可能就是其他值 导致这个本应是包头的4字节变成了比如00 04 00 01 那么这个长度解出来就是远大于10K的一个值 那么显然就是一个非法包 如果说后面凑上来的这一个字节 恰好是 00 解出来包体长度1K 那么就按照正常包处理 继续读取1k的数据 当然由于这个包数据时错位的 那么这个包在解出来之后 交给逻辑层 逻辑层会发现包体里面的数据是乱的 逻辑层自己去处理错误的包 由于这个包错位了一个字节 那么在这个包之后 后面的每一个包肯定都是错的 那么后面肯定能有一个包在解包头的时候 长度不正确 然后将其踢掉 (或者逻辑层已经先一步踢掉这个连接了) 同理 如果是包体少一个字节 最终也会导致解下一个包头出错 然后 在你的这个伪代码里面 我觉得其实有点理想化了 因为 你一开始是无法确定你的这个 case Body: 中的 Bodylent 你能确定的只有HeadMsg.lent 你在收到case Head的时候 应该是根据这个HeadMsg.lent去PostWsaRecv(Body); 收足HeadMsg.lent才会返回 开始解包体 如果还没有凑足HeadMsg.lent 应该是继续PostWsaRecv(Body)直到凑足HeadMsg.lent为止
oyljerry 2013-12-19
  • 打赏
  • 举报
回复
引用 2 楼 yaopeijiang7 的回复:
别闹了,大牛们赶快出来发发骚
可以搞一些认证机制,RSA等,然后客户端用私钥加密一段内容,服务端用公钥解密等。
yaopeijiang7 2013-12-19
  • 打赏
  • 举报
回复
别闹了,大牛们赶快出来发发骚
yaopeijiang7 2013-12-19
  • 打赏
  • 举报
回复
来人啊,版主呢

18,363

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧