简单介绍了目前防火墙领域中的状态检测技术的基本原理
什么是状态检测
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn:
[email protected]
来源:http://yfydz.cublog.cn
状态检测(stateful inspection)是由CheckPoint公司最先提出的,可算是防火墙技术的一项突破性变革,把包过滤的快速性和代理的安全性很好地结合在一起,目前已经是防火墙最流行的检测方式。
状态检测的根本思想是对所有网络数据建立“连接”的概念,此“连接”是面向“连接”的协议之“连接”的扩展,对非连接协议数据也可以建立虚拟连接。既然是连接,必然是有一定的顺序的,通信两边的连接状态也是有一定顺序进行变化的,就象打电话,一定要先拨号对方电话才能振铃,不可能没人拨铃就响了,那样的话一定是哪出了故障。防火墙的状态检测就是事先确定好连接的合法过程模式,如果数据过程符合这个模式,则说明数据是合法正确的,否则就是非法数据,应该被丢
下面用面向连接的TCP协议来作具体说明:
TCP协议是一个标准的面向连接协议,在真正的通信前,必须按一定协议先建立连接,连接建立好后才能通信,通信结束后释放连接。连接建立过程称为三次握手,发起方先发送带有只SYN标志的数据包到目的方,目的方如果端口是打开允许连接的,就会回应一个带SYN和ACK标志的数据包到发起方,发起方收到后再发送一个只带ACK标志的数据包到目地方,目的方收到后就可认为连接已经正确建立;在正常断开时,一方会发送带FIN标志的数据包到对方,表示本方已经不会再发送数据了,但还可以接收数据,对方接收后还可以发数据,发完后也会发带FIN标志的数据包,双方进入断开状态,经过一段时间后连接彻底删除。在异常情况会发送RST标志的包来执行异常断开,不论是在连接开始还是通信和断开过程。
由此可见,第一,TCP的连接过程是一个有序过程,新连接一定是通过SYN包来开始的,如果防火墙里没有相关连接信息,就收到了一个非SYN的包,那该包一定是状态非法的,可以将其扔掉;其二,数据
通信过程是有方向性的,一定是发起方发送SYN,接收方发SYN ACK,不是此方向的数据就是非法的,由此状态检测可以实现A可以访问B而B却不能访问A的效果。
一个连接可以用协议,源地址,目的地址,源端口,目的端口的五元组来唯一确定。
下面看一个具体实现,下面是Linux内核中对TCP协议的状态转换实现表,源码在net/ipv4/
ip_conntrack_proto_tcp.c
#define sNO TCP_CONNTRACK_NONE
#define sES TCP_CONNTRACK_ESTABLISHED
#define sSS TCP_CONNTRACK_SYN_SENT
#define sSR TCP_CONNTRACK_SYN_RECV
#define sFW TCP_CONNTRACK_FIN_WAIT
#define sTW TCP_CONNTRACK_TIME_WAIT
#define sCL TCP_CONNTRACK_CLOSE
#define sCW TCP_CONNTRACK_CLOSE_WAIT
#define sLA TCP_CONNTRACK_LAST_ACK
#define sLI TCP_CONNTRACK_LISTEN
#define sIV TCP_CONNTRACK_MAX
static enum tcp_conntrack tcp_conntracks[2][5][TCP_CONNTRACK_MAX] =
{
{
/* ORIGINAL */
/* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI */
/*syn*/ {sSS, sES, sSS, sSR, sSS, sSS, sSS, sSS, sSS, sLI },
/*fin*/ {sTW, sFW, sSS, sTW, sFW, sTW, sCL, sTW, sLA, sLI },
/*ack*/ {sES, sES, sSS, sES, sFW, sTW, sCL, sCW, sLA, sES },
/*rst*/ {sCL, sCL, sSS, sCL, sCL, sTW, sCL, sCL, sCL, sCL },
/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
},
{
/* REPLY */
/* sNO, sES, sSS, sSR, sFW, sTW, sCL, sCW, sLA, sLI */
/*syn*/ {sSR, sES, sSR, sSR, sSR, sSR, sSR, sSR, sSR, sSR },
/*fin*/ {sCL, sCW, sSS, sTW, sTW, sTW, sCL, sCW, sLA, sLI },
/*ack*/ {sCL, sES, sSS, sSR, sFW, sTW, sCL, sCW, sCL, sLI },
/*rst*/ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sLA, sLI },
/*none*/{sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }
}
};
当一个新SYN包进防火墙时,看上面那个二维数组,由于防火墙里没有该连接信息,会建立新连接,防火墙对该连接状态开始是sNO(无连接),对应第一列,由于是SYN包,对应第一行,因此防火墙收到该包后将连接状态转换为sSS(SYN包发送);当接收方返回SYNACK包进入防火墙时,看下面那个二维数组,当前连接状态是sSS,对应第3列,SYN优先ACK,看第一行,因此防火墙收到该包后将连接状态转换为sSR(收到SYN包);当发起方回复ACK包进入防火墙时,看上面数组,连接当前状态是sSR,对应第4列,ACK包对应第3行,因此防火墙收到该包后将连接状态转换为sES(连接建立),就表示连接已经正确建立。转换表中有不少sIV(非法状态),如果连接状态转换到这里,该包就是非法包。应该要注意的是Linux内核的这个TCP转换表还是属于太过宽容,sIV项太少,对ACK包始终是可以通过的,所以对Linux防火墙,可以用ACK包来扫描端口而不是用SYN包来扫描,要加强防御的话可以修改此转换表。对于面向连接的协议比较好理解防火墙连接的概念,对于非连接协议,如UDP,ICMP等,防火墙同样可以建立连接概念,大部分UDP协议,数据也是有来有往的,如DNS,发一个DNS请求后,服务器会返回结果,因此防火墙可以根据请求包估计出返回包的协议、地址、端口五元组,等回应包到了以后进行相应匹配。同样ICMP,一个ping(echo request)包出去后,可以期望一个echo reply包回来,这也是一个连接过程。
状态检测除了检测到4层外,还可以检测应用层,主要用在多连接的协议,如FTP协议,主连接使用固定端口21进行控制,需要传输数据时会动态打开一个端口来传输数据,可分为主动模式和被动模式,主动模式下FTP服务器使用20端口来连接客户端的动态打开的端口,被动模式下是客户端连接服务器动态打开的端口,因此对于老的普通包过滤防火墙,为支持FTP的被动模式,就必须把端口全部放开。而对于状态检测防火墙,能够解析FTP命令通道中的内容,知道F留出TP将以何种方式在什么端口打开数据通道,从而动态打开相应端口,一旦数据连接结束,该端口就被关闭,因此只需要打开21端口就可以保证FTP的正常通信,安全性比包过滤要强很多。
有了状态检测,就可以很容易实现单向访问,扫描防御,需要打开的端口端口也可以控制在最小范围,具备了代理的安全性,而速度上又不亚于包过滤,目前已经成为防火墙的基本过滤模式。