wafris 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/lua/dist/wafris_core.lua +31 -6
- data/lib/wafris/configuration.rb +5 -15
- data/lib/wafris/middleware.rb +4 -1
- data/lib/wafris/version.rb +1 -1
- data/lib/wafris.rb +3 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 919967ec8203e767f77202e17964dbcfd21f60422bb91bd61b806575886c5dbf
|
4
|
+
data.tar.gz: ffe9b975f6613e1742c90b6335e85f53769d439d32f014517487142a97edb37e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4efff1ae48ec5417bf9917c0a3b7f073064216ee718eed8246f0b993397454ab4296a2e27ac48a1289f31abe20ca277d32f4bc848978a7c4dd88d04ee08c4cdb
|
7
|
+
data.tar.gz: 274d14a646e0e706a940d16c53adb050045df1593056f012ba47666af402c37e38a055038fa2074a73e32e73cc49bcf5f5d943c16e7bff71bd3d79d47e8aaadc
|
@@ -1,5 +1,9 @@
|
|
1
|
-
|
1
|
+
|
2
|
+
|
3
|
+
local USE_TIMESTAMPS_AS_REQUEST_IDS = false
|
2
4
|
local EXPIRATION_IN_SECONDS = 86400
|
5
|
+
local EXPIRATION_OFFSET_IN_SECONDS = 3600
|
6
|
+
|
3
7
|
|
4
8
|
local function get_timebucket(timestamp_in_seconds)
|
5
9
|
local startOfHourTimestamp = math.floor(timestamp_in_seconds / 3600) * 3600
|
@@ -7,6 +11,7 @@ local function get_timebucket(timestamp_in_seconds)
|
|
7
11
|
end
|
8
12
|
|
9
13
|
local function set_property_value_id_lookups(property_abbreviation, property_value)
|
14
|
+
|
10
15
|
local value_key = property_abbreviation .. "V" .. property_value
|
11
16
|
local property_id = redis.call("GET", value_key)
|
12
17
|
|
@@ -15,25 +20,29 @@ local function set_property_value_id_lookups(property_abbreviation, property_val
|
|
15
20
|
redis.call("SET", value_key, property_id)
|
16
21
|
redis.call("SET", property_abbreviation .. "I" .. property_id, property_value)
|
17
22
|
else
|
18
|
-
redis.call("EXPIRE", value_key, EXPIRATION_IN_SECONDS)
|
19
|
-
redis.call("EXPIRE", property_abbreviation .. "I" .. property_id, EXPIRATION_IN_SECONDS)
|
23
|
+
redis.call("EXPIRE", value_key, EXPIRATION_IN_SECONDS + EXPIRATION_OFFSET_IN_SECONDS)
|
24
|
+
redis.call("EXPIRE", property_abbreviation .. "I" .. property_id, EXPIRATION_IN_SECONDS + EXPIRATION_OFFSET_IN_SECONDS)
|
20
25
|
end
|
21
26
|
|
22
27
|
return property_id
|
23
28
|
end
|
24
29
|
|
25
30
|
local function increment_leaderboard_for(property_abbreviation, property_id, timebucket)
|
31
|
+
|
26
32
|
local key = property_abbreviation .. "L" .. timebucket
|
27
33
|
redis.call("ZINCRBY", key, 1, property_id)
|
28
34
|
redis.call("EXPIRE", key, EXPIRATION_IN_SECONDS)
|
29
35
|
end
|
30
36
|
|
31
37
|
local function set_property_to_requests_list(property_abbreviation, property_id, request_id, timebucket)
|
38
|
+
|
32
39
|
local key = property_abbreviation .. "R" .. property_id .. "-" .. timebucket
|
33
40
|
redis.call("LPUSH", key, request_id)
|
34
|
-
|
41
|
+
|
42
|
+
redis.call("EXPIRE", key, EXPIRATION_IN_SECONDS + EXPIRATION_OFFSET_IN_SECONDS)
|
35
43
|
end
|
36
44
|
|
45
|
+
|
37
46
|
local function ip_in_hash(hash_name, ip_address)
|
38
47
|
local found_ip = redis.call('HEXISTS', hash_name, ip_address)
|
39
48
|
|
@@ -45,7 +54,9 @@ local function ip_in_hash(hash_name, ip_address)
|
|
45
54
|
end
|
46
55
|
|
47
56
|
local function ip_in_cidr_range(cidr_set, ip_decimal_lexical)
|
57
|
+
|
48
58
|
local higher_value = redis.call('ZRANGEBYLEX', cidr_set, '['..ip_decimal_lexical, '+', 'LIMIT', 0, 1)[1]
|
59
|
+
|
49
60
|
local lower_value = redis.call('ZREVRANGEBYLEX', cidr_set, '['..ip_decimal_lexical, '-', 'LIMIT', 0, 1)[1]
|
50
61
|
|
51
62
|
if not (higher_value and lower_value) then
|
@@ -64,6 +75,7 @@ end
|
|
64
75
|
|
65
76
|
local function match_by_pattern(property_abbreviation, property_value)
|
66
77
|
local hash_name = "rules-blocked-" .. property_abbreviation
|
78
|
+
|
67
79
|
local patterns = redis.call('HKEYS', hash_name)
|
68
80
|
|
69
81
|
for _, pattern in ipairs(patterns) do
|
@@ -76,10 +88,13 @@ local function match_by_pattern(property_abbreviation, property_value)
|
|
76
88
|
end
|
77
89
|
|
78
90
|
local function blocked_by_rate_limit(request_properties)
|
91
|
+
|
79
92
|
local rate_limiting_rules_values = redis.call('HKEYS', 'rules-blocked-rate-limits')
|
80
93
|
|
81
94
|
for i, rule_name in ipairs(rate_limiting_rules_values) do
|
95
|
+
|
82
96
|
local conditions_hash = redis.call('HGETALL', rule_name .. "-conditions")
|
97
|
+
|
83
98
|
local all_conditions_match = true
|
84
99
|
|
85
100
|
for j = 1, #conditions_hash, 2 do
|
@@ -93,9 +108,13 @@ local function blocked_by_rate_limit(request_properties)
|
|
93
108
|
end
|
94
109
|
|
95
110
|
if all_conditions_match then
|
111
|
+
|
96
112
|
local rule_settings_key = rule_name .. "-settings"
|
113
|
+
|
97
114
|
local limit, time_period, limited_by, rule_id = unpack(redis.call('HMGET', rule_settings_key, 'limit', 'time-period', 'limited-by', 'rule-id'))
|
115
|
+
|
98
116
|
local throttle_key = rule_name .. ":" .. limit .. "V" .. request_properties.ip
|
117
|
+
|
99
118
|
local new_value = redis.call('INCR', throttle_key)
|
100
119
|
|
101
120
|
if new_value == 1 then
|
@@ -113,6 +132,7 @@ end
|
|
113
132
|
|
114
133
|
local function check_rules(functions_to_check)
|
115
134
|
for _, check in ipairs(functions_to_check) do
|
135
|
+
|
116
136
|
local rule = check.func(unpack(check.args))
|
117
137
|
local category = check.category
|
118
138
|
|
@@ -170,13 +190,17 @@ local request = {
|
|
170
190
|
["method_id"] = set_property_value_id_lookups("m", ARGV[8])
|
171
191
|
}
|
172
192
|
|
173
|
-
|
193
|
+
|
194
|
+
|
195
|
+
local current_timebucket = get_timebucket(request.ts_in_seconds)
|
196
|
+
|
174
197
|
local blocked_rule = false
|
175
198
|
local blocked_category = nil
|
176
199
|
local treatment = "p"
|
200
|
+
|
177
201
|
local stream_id
|
178
202
|
|
179
|
-
if
|
203
|
+
if USE_TIMESTAMPS_AS_REQUEST_IDS == true then
|
180
204
|
stream_id = request.ts_in_milliseconds
|
181
205
|
else
|
182
206
|
stream_id = "*"
|
@@ -209,6 +233,7 @@ local request = {
|
|
209
233
|
|
210
234
|
table.insert(stream_args, "ar")
|
211
235
|
table.insert(stream_args, allowed_rule)
|
236
|
+
|
212
237
|
else
|
213
238
|
blocked_rule, blocked_category = check_blocks(request)
|
214
239
|
end
|
data/lib/wafris/configuration.rb
CHANGED
@@ -14,8 +14,10 @@ module Wafris
|
|
14
14
|
)
|
15
15
|
@redis_pool_size = 20
|
16
16
|
|
17
|
-
|
18
|
-
create_settings
|
17
|
+
puts "[Wafris] attempting firewall connection via REDIS_URL."
|
18
|
+
create_settings
|
19
|
+
rescue Redis::CannotConnectError
|
20
|
+
puts "[Wafris] firewall disabled. Cannot connect to REDIS_URL. Will attempt Wafris.configure if it exists."
|
19
21
|
end
|
20
22
|
|
21
23
|
def connection_pool
|
@@ -23,24 +25,12 @@ module Wafris
|
|
23
25
|
ConnectionPool.new(size: redis_pool_size) { redis }
|
24
26
|
end
|
25
27
|
|
26
|
-
def enabled?
|
27
|
-
redis.ping
|
28
|
-
|
29
|
-
return true
|
30
|
-
rescue Redis::CannotConnectError
|
31
|
-
raise <<~CONNECTION_ERROR
|
32
|
-
Wafris cannot connect to Redis.
|
33
|
-
|
34
|
-
The current Redis instance points to a connection that
|
35
|
-
cannot be pinged.
|
36
|
-
CONNECTION_ERROR
|
37
|
-
end
|
38
|
-
|
39
28
|
def create_settings
|
40
29
|
redis.hset('waf-settings',
|
41
30
|
'version', Wafris::VERSION,
|
42
31
|
'client', 'ruby',
|
43
32
|
'redis-host', 'heroku')
|
33
|
+
puts "[Wafris] firewall enabled. Connected to Redis. Ready to process requests. Set rules at: https://wafris.org/hub"
|
44
34
|
end
|
45
35
|
|
46
36
|
def core_sha
|
data/lib/wafris/middleware.rb
CHANGED
@@ -26,12 +26,15 @@ module Wafris
|
|
26
26
|
|
27
27
|
request = Rack::Request.new(env)
|
28
28
|
|
29
|
-
if Wafris.
|
29
|
+
if Wafris.allow_request?(request)
|
30
30
|
@app.call(env)
|
31
31
|
else
|
32
32
|
puts 'blocked'
|
33
33
|
[403, {}, ['Blocked']]
|
34
34
|
end
|
35
|
+
rescue StandardError => e
|
36
|
+
puts "[Wafris] Redis connection error: #{e.message}. Request passed without rules check."
|
37
|
+
@app.call(env)
|
35
38
|
end
|
36
39
|
end
|
37
40
|
end
|
data/lib/wafris/version.rb
CHANGED
data/lib/wafris.rb
CHANGED
@@ -13,7 +13,10 @@ module Wafris
|
|
13
13
|
class << self
|
14
14
|
def configure
|
15
15
|
yield configuration
|
16
|
+
puts "[Wafris] attempting firewall connection via Wafris.configure initializer."
|
16
17
|
configuration.create_settings
|
18
|
+
rescue Redis::CannotConnectError
|
19
|
+
puts "[Wafris] firewall disabled. Cannot connect via Wafris.configure. Please check your configuration settings."
|
17
20
|
end
|
18
21
|
|
19
22
|
def configuration
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wafris
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Micahel Buckbee
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2023-
|
12
|
+
date: 2023-09-07 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: connection_pool
|