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"