i未央 发表于 2014-08-27 16:39

nginx limit_req_zone模块探讨

nginx。
周内碰到一个恶意扫描我们站点的case,现有的policy_frame无法实现,因此想到了limit_req_zone模块,将遇到的问题整理如下,望路过的大牛指点迷津:

【需求】
对如下url通过ip及query string两个维度进行封禁配置
URI: /api/page?id=321&st=xxx
如:若同一ip对/api/page?id=321这个url请求超过100q/10s时就将其封禁

【policy frame】
使用policy frame的URI策略对以/api/page开头的URL进行了限制,如下:

      <DistributeIpAttack define="IP_api_page_1">
            <PolicyTest>N</PolicyTest>
            <BadUserNumThreshold>0</BadUserNumThreshold>
            <BadUserTimePeriod>60</BadUserTimePeriod>
            <CacheNum>500000</CacheNum>
            <TimePeriod>10</TimePeriod>
            <Threshold>100</Threshold>
            <StatID>4</StatID>
      </DistributeIpAttack>

      <Rule type="PRE" skip="100">
          <Pattern>
             <AND>
                <HttpFilter>
                <HTTP_URI match="^/api/page" />
                </HttpFilter>
                <DistributeIpAttack match="IP_api_pageid_1"/>
             </AND>
          </Pattern>
          <Action>
            <ReturnCode Code="13"/>
          </Action>
      </Rule>

这样可以实现对页面的频率限制,但粒度有些大,比如教育网或公共小区出口会存在误伤的情况。恶意扫描只是针对我们某些特定的pageid及id参数,被扫描的页面是变化的,随机,同时,remote_addr是变化的,ip封禁会有误伤,另外也不能根治问题。

【问题】policy frame 能否识别URI中的query string ?

【limit_req_zone模块】
在nginx官网找到了limit_req_zone模块,看介绍似乎可以解决我们的问题,于是就开始朝这方面努力,如下:
【思路】
将$remote_addr和$arg_id组合为一个新变量,用这个变量作为limit的key:

http {
set $limit_key $remote_addr$arg_id   #用remote_addr和uri中的参数id作为新的limit_key
limit_req_zone $limit_keyzone=one:10m rate=10r/s;   #定义$limit_key
}

server {
    location /api/page/ {
    limit_req zone=one burst=5 nodelay;
}
}

大致思路如上,但实现时遇到了问题:nginx http字段中不支持set新的变量:
dota@localhost$ ./sbin/nginx -s reload
nginx: "set" directive is not allowed here in /home/dota/webserver/conf/nginx.conf:87
看来变量不能在http字段里定义。。

于是试着把它挪到了server字段里:

http {
limit_req_zone $limit_keyzone=one:10m rate=10r/s;   #定义$limit_key
}

server {
    set $limit_key $remote_addr$arg_id   #用remote_addr和uri中的参数id作为新的limit_key
    location /api/page/ {
    limit_req zone=one burst=5 nodelay;
}
}

这次,set没有问题,但是nginx还是不认:
nginx: unknown "limit_key" variable

最后,不用set直接在limit_req_zone后跟两个变量:
http {
limit_req_zone $remote_addr$arg_idzone=one:10m rate=10r/s;
}

server {
    location /api/page/ {
    limit_req zone=one burst=5 nodelay;
}
}

运行:
nginx: unknown "remote_addr$arg_id" variable 还是不行。。。


【问题】
1、如果用limit_req_zone模块,可以怎么实现?
2、policy frame是否可以支持query string的封禁?


网路过的大牛指点迷津,在线等~~~

i未央 发表于 2014-08-28 14:30

{:3_185:} 自己顶起

cryboy2001 发表于 2014-08-28 16:00

没用过,不清楚啊。也顶一下吧
页: [1]
查看完整版本: nginx limit_req_zone模块探讨