modSecurity日志收集:在phase 5阶段处理。
由于CC攻击主要考虑对动态请求的防护,所以要排除静态资源的请求,或者自定义动态请求的后缀或者关键字做接口针对性的防护。
定义需要排除的请求url后缀名称
SecAction "id:900260, phase:1, nolog, pass, t:none, setvar:'tx.static_extensions=/.mvc/ /.jpg/ /.jpeg/ /.png/ /.gif/ /.js/ /.css/ /.ico/ /.svg/ /.webp/'"
然后是怎么判断是CC攻击?根据访问频率来定义,某个ip在dos_burst_time_slice的时间(单位秒)内dos_counter_threshold次请求算一次攻击嫌疑,如果超过2次,我们就认定是CC攻击的IP,对该IP封禁,解封时间定义为dos_block_timeout。
例如,定义60s内100次动态请求算一次攻击嫌疑,封禁时间为600s。
SecAction "id:900700, phase:1, nolog, pass, t:none, setvar:'tx.dos_burst_time_slice=60', setvar:'tx.dos_counter_threshold=100', setvar:'tx.dos_block_timeout=600'"
接下来就是关键的拦截策略了。
总体思路如下:
1、如果一个请求访问的是非静态(TX:STATIC_EXTENSIONS)资源,那我们就定义一个变量(IP:DOS_COUNTER)+1,IP为客户端IP
SecRule REQUEST_BASENAME ".*?(.[a-z0-9]{1,10})?$" "phase:5, id:912150, t:none, t:lowercase, nolog, pass, tag:'application-multi', tag:'language-multi', tag:'platform-multi', tag:'attack-dos', capture, setvar:tx.extension=/%{TX.1}/, chain" SecRule TX:EXTENSION "!@within %{tx.static_extensions}" "setvar:ip.dos_counter=+1"
2、如果IP:DOS_COUNTER大于TX:DOS_COUNTER_THRESHOLD阈值,就创建一个CC嫌疑次数IP:DOS_BURST_COUNTER=1,如果存在则该值设置为2。且IP:DOS_COUNTER置0,CC嫌疑次数IP:DOS_BURST_COUNTER有一个超时时间TX:DOS_BURST_TIME_SLICE。
SecRule IP:DOS_COUNTER "@ge %{tx.dos_counter_threshold}" "phase:5, id:912160, t:none, nolog, pass, tag:'application-multi', tag:'language-multi', tag:'platform-multi', tag:'attack-dos', chain" SecRule &IP:DOS_BURST_COUNTER "@eq 0" "setvar:ip.dos_burst_counter=1, expirevar:ip.dos_burst_counter=%{tx.dos_burst_time_slice}, setvar:!ip.dos_counter" SecRule IP:DOS_COUNTER "@ge %{tx.dos_counter_threshold}" "phase:5, id:912161, t:none, nolog, pass, tag:'application-multi', tag:'language-multi', tag:'platform-multi', tag:'attack-dos', chain" SecRule &IP:DOS_BURST_COUNTER "@ge 1" "setvar:ip.dos_burst_counter=2, expirevar:ip.dos_burst_counter=%{tx.dos_burst_time_slice}, setvar:!ip.dos_counter"
3、如果CC嫌疑次数IP:DOS_BURST_COUNTER大于2就认定为CC攻击,定义一个值IP:DOS_BLOCK,该变量超时时间为TX:DOS_BLOCK_TIMEOUT。
定义大于等于两次封IP的规则:如果IP:DOS_BURST_COUNTER大于等于2,设置变量ip.dos_block=1,且设置该变量的超时时间为TX:DOS_BLOCK_TIMEOUT。在phase5发生。
SecRule IP:DOS_BURST_COUNTER "@ge 2" "phase:5, id:912170, t:none, log, pass, tag:'application-multi', tag:'language-multi', tag:'platform-multi', tag:'attack-dos', msg:'Potential Denial of Service (DoS) Attack from %{tx.real_ip} - # of Request Bursts: %{ip.dos_burst_counter}', setvar:ip.dos_block=1, expirevar:ip.dos_block=%{tx.dos_block_timeout}"
4、在phase1,如果IP:DOS_BLOCK为1,则阻断该请求,且IP:DOS_BLOCK_COUNTER+=1。如果一个IP第一次被阻断,记录阻断日志并设置一个IP:DOS_BLOCK_FLAG 标志,该标志的超时时间为60s,设置该标志的后面不记录日志,避免刷屏。也就是说如果一直攻击,最多60s记录一次日志。为了显示IP:DOS_BLOCK_COUNTER的同时重置该值,将IP:DOS_BLOCK_COUNTER复制到TX:DOS_BLOCK_COUNTER这个变量。
# # Block and track # of requests and log # SecRule IP:DOS_BLOCK "@eq 1" "chain, phase:1, id:912120, drop, tag:'application-multi', tag:'language-multi', tag:'platform-multi', tag:'attack-dos', msg:'Denial of Service (DoS) attack identified from %{tx.real_ip} (%{tx.dos_block_counter} hits since last alert)'" SecRule &IP:DOS_BLOCK_FLAG "@eq 0" "setvar:ip.dos_block_counter=+1, setvar:ip.dos_block_flag=1, expirevar:ip.dos_block_flag=60, setvar:tx.dos_block_counter=%{ip.dos_block_counter}, setvar:ip.dos_block_counter=0"
SecRule IP:DOS_BLOCK "@eq 1" "phase:1, id:912130, t:none, drop, nolog, tag:'application-multi', tag:'language-multi', tag:'platform-multi', tag:'attack-dos', setvar:ip.dos_block_counter=+1"