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;
	}

}


 

發佈了57 篇原創文章 · 獲贊 21 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章