-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathratelimit.conf
119 lines (107 loc) · 5.72 KB
/
ratelimit.conf
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# ------------------------------------------------------------------------------------------------------
# --. Ratelimiting ONLY CONSIDERING modsecurity denials .--
#
# WHY? Imagine a cracker with a batch of thousands requests trying to xploit any website vulnerability...
# Modsecurity will stop hits, ok, and then LFD firewall may block that IP... ok.. but what happens until LFD blocks????
# Huge number of xploiting request could be received until LFD blocks, maybe one of them may not trigger the modsecurity rules,
# and ooops, xploit has been done!! We may not receive minutes of xploiting requests waiting for LFD actions, so this
# ratelimit may BLOCK that IP if it triggers the current denials limit... it is going to be "blocked" BEFORE LFD ban the IP.
#
# Must compile libmodsecurity with (--with-lmdb). Also compile using LUA: ensure LUA is present when libmodsecurity configure
# before compiling libmodsecurity install liblua5.3-0 and liblua5.3-dev for example!
#
# Also MUST configure "working_directory" variable at /etc/nginx/nginx.conf, selecting something like /var/modsecurity, and
# SHOULD be writeable by user running nginx, as 'nginx' or 'www-data' for example.
#
# Skipping libmodsecurity v2 functions to decrease values, as v3 does not support yet 'deprecatevar' or 'expirevar' functions
# Using LUA script to decrease. It's a modified version of: https://github.com/loadbalancerorg/modsec_decrement_script
#
# Decreasing hits via lua script will be done only when processing a new request, and will consider how much time it took...
# Also consider removing modsec-shared-collections* and reloading nginx from time to time to clean-up database and remove old garbage.
#
# If using this script, should:
#
# - libmodsecurity configure with --with-lmdb, to work with modsec-shared-collections
# - ensure lua and lua-dev packages are installed in the system, so libmodsecurity is configured to work with lua.
# - nginx configuration variable "working_directory" set to a writable directory for nginx user (nginx, www-data, nobody or whatever).
# - work with CRS OWASP package of rules (at least v3)
# - set the script path for lua in the rule id:5001 below!
# - Execute this after loading CRS OWASP rules: "SecRuleRemoveById 901321"
# - Configure maximum_hit_requests, lua_interval and lua_decrease in the rule id:5000 below!
# ------------------------------------------------------------------------------------------------------
# Define variables (lua_* variables are defined for LUA script)
# Define maximum_hit_requests, and how much the count decreases in time: lua_decrease each lua_interval
# in seconds: each 'lua_interval seconds', the count may decrease in 'lua_decrease'
#
# Also Init collection by IP address (this collection may be removed if it does not trigger a HIT)
# Read: https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-%28v3.x%29#persistent-storage
#
# At the end, for compatibility, just add global collection and seet tx.real_ip variable, as done by OWASP CRS 901321 rule.
SecAction \
"id:5000,\
phase:1,\
pass,\
t:none,\
nolog,\
noauditlog,\
setvar:'TX.maximum_hit_requests=15',\
setvar:'TX.lua_hits=ip.hits_count',\
setvar:'TX.lua_epoch=ip.hits_epoch',\
setvar:'TX.lua_interval=120',\
setvar:'TX.lua_decrease=1',\
setvar:'TX.lua_current_time=%{TIME_EPOCH}',\
initcol:ip=%{remote_addr},\
initcol:global=global,\
setvar:'tx.real_ip=%{remote_addr}'\
"
# ------------------------------------------------------------------------------------------------------
# Decreasing count of hits using LUA script (does not trigger in phase 1, don't know why)
SecAction \
"id:5001,\
phase:2,\
nolog,\
noauditlog,\
pass,\
t:none,\
exec:/etc/modsecurity/custom-rules/ratelimit.lua \
"
# ------------------------------------------------------------------------------------------------------
# If number of hits triggering errors is equal or greater than defined %{TX.maximum_hit_requests}
# he request will be denied, INSTANTLY! No more processing... it doesn't matter if request is legit!
# IP should be blocked as it triggered the limit, no way to consider legit requests from now on.
# This way we stop the possible batch of xploiting requests from now on.
# (note: this request is considered to increment hits, incrementing hits_count.
SecRule IP:hits_count "@ge %{TX.maximum_hit_requests}" \
"id:5002,\
phase:2,\
drop,\
t:none,\
status:406,\
log,\
auditlog, \
logdata:'%{remote_addr} hit count: %{ip.hits_count}/%{TX.maximum_hit_requests} hits/max. Allowed %{TX.lua_decrease}/%{TX.lua_interval} req/s',\
msg:'ModSecurity ratelimited',\
tag:'Triggered-ratelimit',\
setvar:'ip.hits_count=+1'\
"
# ------------------------------------------------------------------------------------------------------
# And that's all!! Now incrementing the hits_count... we will do it starting the phase 3, after
# phase 2 (incoming) checks, so OWASP TX:ANOMALY_SCORE is well defined...
SecRule TX:ANOMALY_SCORE "@ge %{tx.inbound_anomaly_score_threshold}" \
"id:5003,\
phase:3,\
pass,\
t:none,\
nolog,\
auditlog,\
logdata:'%{remote_addr} hit count: %{ip.hits_count}/%{TX.maximum_hit_requests} hits/max. Allowed %{TX.lua_decrease}/%{TX.lua_interval} req/s',\
setvar:'ip.hits_count=+1'\
"
# ------------------------------------------------------------------------------------------------------
# Just one important note!!! We are using CRS OWASP rules... they also perform an initcol:ip but adding
# user-agent to the key... it is modifying our collection, so unique solution is disabling CRS rule
# at the end, after loading CRS... using for example: /etc/modsecurity/custom-rules/post-engine-rules.conf
#
# Do not try to SecRuleRemoveById here! Just write this one after loading CRS OWASP rules:
#
# SecRuleRemoveById 901321