SYN-Cookie概述
预防半连接攻击,SYN-Cookie是一种有效的机制,它的基本原理非常简单,那就是“完成三次握手前不为任何一个连接分配任何资源”,它是怎么做到的呢?也是非常简单。
序列号 | CPU | RAM | HDD | 带宽 | 售价(美元) | 免费试用 |
---|---|---|---|---|---|---|
香港服务器1 | E5-2620 | 32G | 1T HDD | 50M/无限流量 | $196.00 | 立即申请 |
香港服务器2 | E5-2650 | 32G | 1T HDD | 50M/无限流量 | $256.00 | 立即申请 |
香港服务器3 | E5-2680 | 32G | 1T HDD | 50M/无限流量 | $316.00 | 立即申请 |
香港服务器4 | E5-2690 | 32G | 1T HDD | 50M/无限流量 | $336.00 | 立即申请 |
香港服务器5 | E5-2697 | 32G | 1T HDD | 50M/无限流量 | $376.00 | 立即申请 |
香港服务器6 | E5-2620*2 | 32G | 1T HDD | 50M/无限流量 | $376.00 | 立即申请 |
香港服务器7 | E5-2650*2 | 32G | 1T HDD | 50M/无限流量 | $436.00 | 立即申请 |
香港服务器8 | E5-2680*2 | 32G | 1T HDD | 50M/无限流量 | $476.00 | 立即申请 |
香港服务器9 | E5-2690*2 | 32G | 1T HDD | 50M/无限流量 | $556.00 | 立即申请 |
香港服务器10 | E5-2697*2 | 32G | 1T HDD | 50M/无限流量 | $596.00 | 立即申请 |
香港服务器11 | E5-2680v4*2 | 32G | 1T HDD | 50M/无限流量 | $696.00 | 立即申请 |
香港服务器12 | E5-2698v4*2 | 32G | 1T HDD | 50M/无限流量 | $796.00 | 立即申请 |
1.编码信息
将一些本应该在本地保存的信息编码到返回给客户端的SYN-ACK的初始化序列号或者时间戳里面。握手尚未完成不分配任何资源(Linux即不分配request结构体)。
2.解码信息
等到客户端的ACK最终到来的时候,再从ACK序列号里面解码出保存的信息。
3.建立连接
利用第2步解码出来的信息建立一个TCP连接,此时因为握手已经完成,可以分配资源了。我们接下来通过图示和代码来看一下编码和解码的过程。
编码过程图示
解码过程图示
问题
通过上面的编码解码过程中好像没有什么check/compare操作,一般而言,对于类似HASH或者摘要的算法,都需要对信息进行比对,比如对一段信息生产一个摘要,为了确保该信息没有被篡改,需要再次使用相同的算法生成摘要,如果两段摘要的值不同,说明信息被篡改了!对于上面的算法,在生产Cookie的时候,我们注意到使用hash算法对元组生产了一个值,但是对于解码的过程,它并没有再次计算这个值与原始携带的值做比对,这样合理吗?
这事实上是Linux的一个hack!Linux将一段data做了限定,比如它的值严格在0-7之间,将这个data一同参与运算,而不是仅仅将其编码到固定的某几个bit,算法寄希望于:如果数据是伪造的或者被篡改了,那么解码出来的data的值仍然处在规定的严格区间里的可能性微乎其微!
测试代码
我们来看一个用户态的测试代码,说明一下24比特数据的编码和解码的过程:
#include
#include
#include
typedef unsigned int u32;
#define COOKIEBITS 24 /* Upper bits store count */
#define COOKIEMASK (((u32)1 << COOKIEBITS) - 1)
// 简单hash函数,只为测试!
static u32 cookie_hash(u32 saddr, u32 daddr, u32 count, int c)
{
u32 tmp = (saddr + daddr - c) & ((u32)-1);
return tmp;
}
// 编码过程
static u32 syn_cookie(u32 saddr, u32 daddr, u32 sseq, u32 count, u32 data)
{
return (cookie_hash(saddr, daddr, 0, 0) +
sseq + (count << COOKIEBITS) +
((cookie_hash(saddr, daddr, count, 1) + data) & COOKIEMASK));
}
// 解码过程
static u32 check_syn_cookie(u32 cookie, u32 saddr, u32 daddr, u32 sseq, u32 count, u32 maxdiff)
{
u32 diff;
cookie -= cookie_hash(saddr, daddr, 0, 0) + sseq;
diff = (count - (cookie >> COOKIEBITS)) & ((u32) - 1 >> COOKIEBITS);
if (diff >= maxdiff) {
return (u32)-1;
}
return (cookie - cookie_hash(saddr, daddr, count - diff, 1)) & COOKIEMASK;
}
int main()
{
u32 saddr = 0x11223344, daddr = 0x23456789;
u32