更新时间:2024-12-24 GMT+08:00

通过水印防护抵御CC攻击

通过在业务端共享水印算法和关键字,客户端发出的报文都镶嵌入水印特征,能有效抵御四层CC攻击。

通常UDP Flood的防御方式有两种,一种是动态指纹学习,一种是UDP限流,前者可能会将正常的业务载荷学习成攻击指纹,容易造成误杀,后者会将正常流量和攻击流量一起进行阻断,影响您的正常业务使用。

图1 设备防护原理图

图2所示,华为云解决方案通过在UDP报文中增加水印头部信息,用以标识正常的业务报文,线下DDoS防护设备在接收到UDP报文后,通过检查UDP水印的正确性,可以高效准确放行正常的业务报文,阻断攻击报文。

图2 水印解决方案

客户端和DDoS防护设备需要使用相同的信息结构和计算规则,其中计算规则是指计算水印值的哈希因子和哈希算法,在本方案中,哈希因子使用了目的IP、目的端口、用户标识和水印关键字,哈希算法使用CRC32。

约束与限制

  • 该功能需要客户端同步开发,如果需要使用,请提交工单申请开通。
  • 一个水印最多可以配置两条关键字。

开启水印防护

您可以通过控制台设置水印防护策略,并在客户端配置水印。

  1. 登录管理控制台
  2. 在页面上方选择“区域”后,单击页面左上方的,选择安全与合规 > DDoS防护 AAD,进入“Anti-DDoS流量清洗”界面。
  3. 在左侧导航栏选择DDoS原生高级防护 > 防护策略,进入DDoS原生高级防护“防护策略”页面。
  4. 在防护策略列表的左上方,单击“创建策略”
  5. 在弹出的“创建策略”对话框中,设置“策略名称”并选择所属实例后,单击“确定”

    图3 创建策略

  6. 在目标防护策略所在行的“操作”列中,单击“配置策略”
  7. “水印防护”配置框中,单击“自定义防护”

    图4 水印防护配置框

  8. 在弹出的“水印防护设置”页面中,单击“新建水印”
  9. “新建水印”对话框中,设置水印参数。

    图5 新建水印
    表1 水印参数说明

    参数

    说明

    水印名称

    输入水印名称。

    协议

    当前仅支持UDP协议。

    关键字

    输入关键字,最多可输入两个关键字。

    端口范围

    支持的端口范围为1~65535。

  10. 单击“确定”,水印添加成功。

本节主要以C语言进行示例,指导客户端开发人员如何在客户端实现UDP水印的计算和添加,开发人员可以根据实现开发平台进行代码调整。

  1. 初始化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;
        }
    }

  2. 计算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;
    }

  3. 计算报文的水印值示例代码。计算水印信息结构如图6所示。

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

  4. 将计算出的CRC哈希值,按图7结构填充到报文中,然后发送出去。

    图7 填充报文UDP水印