通过水印防护抵御CC攻击
通过在业务端共享水印算法和关键字,客户端发出的报文都镶嵌入水印特征,能有效抵御四层CC攻击。
通常UDP Flood的防御方式有两种,一种是动态指纹学习,一种是UDP限流,前者可能会将正常的业务载荷学习成攻击指纹,容易造成误杀,后者会将正常流量和攻击流量一起进行阻断,影响您的正常业务使用。
如图2所示,华为云解决方案通过在UDP报文中增加水印头部信息,用以标识正常的业务报文,线下DDoS防护设备在接收到UDP报文后,通过检查UDP水印的正确性,可以高效准确放行正常的业务报文,阻断攻击报文。
客户端和DDoS防护设备需要使用相同的信息结构和计算规则,其中计算规则是指计算水印值的哈希因子和哈希算法,在本方案中,哈希因子使用了目的IP、目的端口、用户标识和水印关键字,哈希算法使用CRC32。
约束与限制
- 该功能需要客户端同步开发,如果需要使用,请提交工单申请开通。
- 一个水印最多可以配置两条关键字。
开启水印防护
您可以通过控制台设置水印防护策略,并在客户端配置水印。
- 登录管理控制台。
- 在页面上方选择“区域”后,单击页面左上方的,选择 ,进入“Anti-DDoS流量清洗”界面。
- 在左侧导航栏选择“防护策略”页面。 ,进入DDoS原生高级防护
- 在防护策略列表的左上方,单击“创建策略”。
- 在弹出的“创建策略”对话框中,设置“策略名称”并选择所属实例后,单击“确定”。
图3 创建策略
- 在目标防护策略所在行的“操作”列中,单击“配置策略”。
- 在“水印防护”配置框中,单击“自定义防护”。
图4 水印防护配置框
- 在弹出的“水印防护设置”页面中,单击“新建水印”。
- 在“新建水印”对话框中,设置水印参数。
图5 新建水印
表1 水印参数说明 参数
说明
水印名称
输入水印名称。
协议
当前仅支持UDP协议。
关键字
输入关键字,最多可输入两个关键字。
端口范围
支持的端口范围为1~65535。
- 单击“确定”,水印添加成功。
本节主要以C语言进行示例,指导客户端开发人员如何在客户端实现UDP水印的计算和添加,开发人员可以根据实现开发平台进行代码调整。
- 初始化CRC表:
unsigned int g_szCRCTable[256]; void CRC32TableInit(void) { unsigned int c; int n, k; for (n = 0; n < 256; n++) { c = (unsigned int)n; for (k = 0; k < 8; k++) { if (c & 1) { c = 0xedb88320 ^ (c >> 1); } else { c = c >> 1; } } g_szCRCTable[n] = c; } }
- 计算CRC哈希值的接口,其中第一个参数crc默认使用0即可。
unsigned int CRC32Hash(unsigned int crc, unsigned char* buf, int len) { unsigned int c = crc ^ 0xFFFFFFFF; int n; for (n = 0; n < len; n++) { c = g_szCRCTable[(c ^ buf[n]) & 0xFF] ^ (c >> 8); } return c ^ 0xFFFFFFFF; }
- 计算报文的水印值示例代码。计算水印信息结构如图6所示。
- 水印数据结构定义如下代码所示:
- 字节序需要使用网络序。
- 业务载荷不满4字节的,使用0进行填充。
typedef struct { unsigned int userId; /* 用户标识ID */ unsigned int payload; /* 业务载荷 */ unsigned short destPort; /* 业务目的端口 */ unsigned short rsv; /* 保留字段,2字节填充 */ unsigned int destIp; /* 业务目的IP */ unsigned int key; /* 水印关键字 */ } UdpWatermarkInfo;
- 计算CRC哈希值可以使用CPU硬件加速接口进行替换,以提升处理性能。
unsigned int UdpFloodWatermarkHashGet(unsigned int userId, unsigned int payload, unsigned short destPort, unsigned int destIp, unsigned int key) { UdpWatermarkInfo stWaterInfo; stWaterInfo.destIp = destIp; stWaterInfo.destPort = destPort; stWaterInfo.userId = userId; stWaterInfo.payload = payload; stWaterInfo.key = key; stWaterInfo.rsv = 0; return CRC32Hash(0, (UCHAR *)&stWaterInfo, sizeof(stWaterInfo)); }
- 水印数据结构定义如下代码所示:
- 将计算出的CRC哈希值,按图7结构填充到报文中,然后发送出去。