Netty学习10-Netty的socket攻击及预防

在前面的文章我们说到过,可以采用长度+数据的格式定义包结构;但是如果长度定义的特别大,那么缓冲区必然会存储不下,而引起宕机或其他问题。这便是一种socket攻击。

除此之外,如果定义的长度和实际长度不匹配,比如实际长度为5,定义的长度为6,那么读取的时候可能会把下一个数据包的一部分读取到,造成以后的数据不能正常解析;这也是一种socket攻击。

可以通过以下几个方面处理socket攻击:

1.定义字节的最大长度,如果字节流大于Max,跳过所有字节流

  // 防止Socket攻击
    if (buffer.readableBytes() > 2048) {
      buffer.skipBytes(buffer.readableBytes());
      return null;
    }
2.但是当跳过所有字节流后,可用包头定位到下一个正确的数据包开始的地方,所以标准包结构还应该有个起始的包头标志。跳过最大长度后,循环读取数据包一个字节,判断是否是包头;如果不是则跳过继续读,直到读到包头,跳出循环,然后才可以继续解析;但是这个过程可能会在读的过程中长度小于最小包结构长度了,这时候要直接返回null,等待下次数据到来后再解析;

具体代码如下:

package com.cn.codc;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.FrameDecoder;
import com.cn.constant.ConstantValue;
import com.cn.model.Response;

/**
 * response解码器
 * <pre>
 * 数据包格式
 * +——----——+——-----——+——----——+——----——+——-----——+——-----——+
 * | 包头          | 模块号        | 命令号       |  状态码    |  长度          |   数据       |
 * +——----——+——-----——+——----——+——----——+——-----——+——-----——+
 * </pre>
 * 包头4字节
 * 模块号2字节short
 * 命令号2字节short
 * 长度4字节(描述数据部分字节长度)
 * 
 -
 *
 */
public class ResponseDecoder extends FrameDecoder{
	
	/**
	 * 数据包基本长度
	 */
	public static int BASE_LENTH = 4 + 2 + 2 + 4;

	@Override
	protected Object decode(ChannelHandlerContext arg0, Channel arg1, ChannelBuffer buffer) throws Exception {
		
		//可读长度必须大于基本长度
		if(buffer.readableBytes() >= BASE_LENTH){
			//防止字节流攻击
			if(buffer.readableBytes()>2048){
			//清除缓存中的数据
				buffer.skipBytes(buffer.readableBytes());
			}
			//记录包头开始的index
			int beginReader ;
			
			while(true){
				beginReader = buffer.readerIndex();
				//标记当前索引
				buffer.markReaderIndex();
				//判断包头是否是当前的包头
				//因为清除了数据之后,因为可能会出现分包截断的现象,下次进来的时候,
				//可能不是开头,所以不能知道哪个是长度,哪个是数据,所以需要包头,
				//只有当时读到包头的时候才继续往下走。
				if(buffer.readInt() == ConstantValue.FLAG){
					break;
				}
				//未读到包头超过了一个字节
				buffer.resetReaderIndex();
				//因为可能读一个int之后,略过了包头,因为可能包头在第一个字节处
				//所以这里选择继续往下读一个字节
				buffer.readByte();
				//可能出现极端的情况,长度又变得不满足
				if(buffer.readableBytes()<BASE_LENGTH){
					return null
				}
			}
			
			//模块号
			short module = buffer.readShort();
			//命令号
			short cmd = buffer.readShort();
			//状态码
			int stateCode = buffer.readInt();
			//长度
			int length = buffer.readInt();
			
			if(buffer.readableBytes() < length){
				//还原读指针
				buffer.readerIndex(beginReader);
				return null;
			}
			
			byte[] data = new byte[length];
			buffer.readBytes(data);
			
			Response response = new Response();
			response.setModule(module);
			response.setCmd(cmd);
			response.setStateCode(stateCode);
			response.setData(data);
			
			//继续往下传递 
			return response;
			
		}
		//数据包不完整,需要等待后面的包来
		return null;
	}

}


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值