aikido-zen 1.7.2.beta.2 → 1.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/docs/request-bypassing.md +38 -0
- data/lib/aikido/zen/context.rb +5 -0
- data/lib/aikido/zen/middleware/allowed_address_checker.rb +3 -2
- data/lib/aikido/zen/middleware/attack_protector.rb +1 -1
- data/lib/aikido/zen/middleware/attack_wave_protector.rb +2 -3
- data/lib/aikido/zen/middleware/ip_list_checker.rb +1 -5
- data/lib/aikido/zen/middleware/rack_throttler.rb +1 -1
- data/lib/aikido/zen/middleware/request_tracker.rb +8 -8
- data/lib/aikido/zen/middleware/user_agent_checker.rb +1 -5
- data/lib/aikido/zen/sinks/action_controller.rb +1 -1
- data/lib/aikido/zen/sinks/async_http.rb +1 -3
- data/lib/aikido/zen/sinks/curb.rb +1 -3
- data/lib/aikido/zen/sinks/em_http.rb +1 -3
- data/lib/aikido/zen/sinks/excon.rb +1 -3
- data/lib/aikido/zen/sinks/http.rb +1 -3
- data/lib/aikido/zen/sinks/httpclient.rb +1 -3
- data/lib/aikido/zen/sinks/httpx.rb +1 -3
- data/lib/aikido/zen/sinks/net_http.rb +1 -3
- data/lib/aikido/zen/sinks/patron.rb +1 -3
- data/lib/aikido/zen/sinks/typhoeus.rb +1 -3
- data/lib/aikido/zen/version.rb +1 -1
- data/lib/aikido/zen.rb +17 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 41f1982e134a806c513cc166247059c3f290f6bbc88ff32dcf4bdc65da9f377d
|
|
4
|
+
data.tar.gz: d97dac2f830555239836a143b815ca3c85c4993776183ce73bc5dc392fed9618
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 526140c45a47c29f4f36e1508bc3305bafe535e92479c877deeb92a1f74c618fa19d7c46a7d67183310fbc414f05912b93c88f2cdb109730d04c0b4b6a54b301
|
|
7
|
+
data.tar.gz: 6c43bc7461a52ded8331b6ba2188afd9d273e1b012f5912b2d9786c439e2890380003779925bd3f37fdd4422f4b34aefe13af6d29d0a6a7f3b4e351c5019dca1
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Bypass Zen for a specific request
|
|
2
|
+
|
|
3
|
+
To disable Zen for a specific request, call `Aikido::Zen.request_bypassed!` from a Rack middleware. This bypasses Zen's security checks and stats collection for that request.
|
|
4
|
+
|
|
5
|
+
> [!NOTE]
|
|
6
|
+
> Zen already has a built-in feature for bypassing specific IP addresses. This feature offers more flexibility, letting you bypass Zen for a request based on any criteria you choose.
|
|
7
|
+
|
|
8
|
+
`Aikido::Zen.request_bypassed!` needs the request's context to already be set up, so your middleware must run after Zen's `ContextSetter` middleware. The following example shows how to bypass a specific request in a Rails application:
|
|
9
|
+
|
|
10
|
+
```ruby
|
|
11
|
+
# config/application.rb
|
|
12
|
+
class RequestBypasser
|
|
13
|
+
def initialize(app)
|
|
14
|
+
@app = app
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def call(env)
|
|
18
|
+
if your_custom_logic?(env)
|
|
19
|
+
Aikido::Zen.request_bypassed! # Bypasses Zen for this request
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
@app.call(env)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module YourApp
|
|
27
|
+
class Application < Rails::Application
|
|
28
|
+
# ...
|
|
29
|
+
|
|
30
|
+
initializer "your_app.insert_request_bypasser", after: "aikido.add_middleware" do |app|
|
|
31
|
+
app.middleware.insert_after Aikido::Zen::Middleware::ContextSetter, RequestBypasser
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
> [!WARNING]
|
|
38
|
+
> Use this feature with caution, as it can potentially expose your application to security risks if not used properly.
|
data/lib/aikido/zen/context.rb
CHANGED
|
@@ -24,6 +24,10 @@ module Aikido::Zen
|
|
|
24
24
|
attr_accessor :scanning
|
|
25
25
|
alias_method :scanning?, :scanning
|
|
26
26
|
|
|
27
|
+
# @return [Boolean, nil] whether the request is bypassed.
|
|
28
|
+
attr_accessor :request_bypassed
|
|
29
|
+
alias_method :request_bypassed?, :request_bypassed
|
|
30
|
+
|
|
27
31
|
# @return [Boolean] whether attack protection for the currently requested
|
|
28
32
|
# endpoint was disabled on the Aikido dashboard, or if the source IP for
|
|
29
33
|
# this request is in the "Bypass List".
|
|
@@ -48,6 +52,7 @@ module Aikido::Zen
|
|
|
48
52
|
|
|
49
53
|
@metadata = {}
|
|
50
54
|
@scanning = false
|
|
55
|
+
@request_bypassed = nil
|
|
51
56
|
@protection_disabled = false
|
|
52
57
|
@idor_protection_enabled = false
|
|
53
58
|
end
|
|
@@ -5,8 +5,9 @@ module Aikido::Zen
|
|
|
5
5
|
# Middleware that only allows allowed IPs when allowed IPs are configured for
|
|
6
6
|
# any matching route in the Aikido dashboard.
|
|
7
7
|
class AllowedAddressChecker
|
|
8
|
-
def initialize(app,
|
|
8
|
+
def initialize(app, zen: Aikido::Zen, config: zen.config, settings: zen.runtime_settings)
|
|
9
9
|
@app = app
|
|
10
|
+
@zen = zen
|
|
10
11
|
@config = config
|
|
11
12
|
@settings = settings
|
|
12
13
|
end
|
|
@@ -22,7 +23,7 @@ module Aikido::Zen
|
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
private def allowed?(request)
|
|
25
|
-
return true if @
|
|
26
|
+
return true if @zen.request_bypassed?
|
|
26
27
|
|
|
27
28
|
matches = @settings.endpoints.matched_settings(request.route)
|
|
28
29
|
|
|
@@ -19,7 +19,7 @@ module Aikido::Zen
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
private def protection_disabled?(request)
|
|
22
|
-
return true if @
|
|
22
|
+
return true if @zen.request_bypassed?
|
|
23
23
|
|
|
24
24
|
!@settings.endpoints.matched_settings(request.route).all?(&:protected?)
|
|
25
25
|
end
|
|
@@ -4,10 +4,9 @@ module Aikido
|
|
|
4
4
|
module Zen
|
|
5
5
|
module Middleware
|
|
6
6
|
class AttackWaveProtector
|
|
7
|
-
def initialize(app, zen: Aikido::Zen
|
|
7
|
+
def initialize(app, zen: Aikido::Zen)
|
|
8
8
|
@app = app
|
|
9
9
|
@zen = zen
|
|
10
|
-
@settings = settings
|
|
11
10
|
end
|
|
12
11
|
|
|
13
12
|
def call(env)
|
|
@@ -30,7 +29,7 @@ module Aikido
|
|
|
30
29
|
request = context.request
|
|
31
30
|
return nil if request.nil?
|
|
32
31
|
|
|
33
|
-
return nil if @
|
|
32
|
+
return nil if @zen.request_bypassed?
|
|
34
33
|
|
|
35
34
|
@zen.detect_attack_wave(context, status_code)
|
|
36
35
|
end
|
|
@@ -15,7 +15,7 @@ module Aikido::Zen
|
|
|
15
15
|
|
|
16
16
|
client_ip = request.client_ip
|
|
17
17
|
|
|
18
|
-
return @app.call(env) if
|
|
18
|
+
return @app.call(env) if @zen.request_bypassed?
|
|
19
19
|
|
|
20
20
|
if !@settings.allowed_ip?(client_ip)
|
|
21
21
|
return @config.blocked_responder.call(request, :ip_allowed_list)
|
|
@@ -38,10 +38,6 @@ module Aikido::Zen
|
|
|
38
38
|
|
|
39
39
|
@app.call(env)
|
|
40
40
|
end
|
|
41
|
-
|
|
42
|
-
def bypassed_ip?(client_ip)
|
|
43
|
-
@settings.bypassed_ips.include?(client_ip)
|
|
44
|
-
end
|
|
45
41
|
end
|
|
46
42
|
end
|
|
47
43
|
end
|
|
@@ -34,7 +34,7 @@ module Aikido::Zen
|
|
|
34
34
|
private
|
|
35
35
|
|
|
36
36
|
def should_throttle?(request)
|
|
37
|
-
return false if @
|
|
37
|
+
return false if @zen.request_bypassed?
|
|
38
38
|
|
|
39
39
|
return false if request.actor && @settings.user_excluded_from_rate_limiting?(request.actor.id)
|
|
40
40
|
|
|
@@ -5,8 +5,9 @@ module Aikido::Zen
|
|
|
5
5
|
# Rack middleware used to track request
|
|
6
6
|
# It implements the logic under that which is considered worthy of being tracked.
|
|
7
7
|
class RequestTracker
|
|
8
|
-
def initialize(app,
|
|
8
|
+
def initialize(app, zen: Aikido::Zen, settings: zen.runtime_settings)
|
|
9
9
|
@app = app
|
|
10
|
+
@zen = zen
|
|
10
11
|
@settings = settings
|
|
11
12
|
end
|
|
12
13
|
|
|
@@ -17,13 +18,12 @@ module Aikido::Zen
|
|
|
17
18
|
if request.route && track?(
|
|
18
19
|
status_code: response[0],
|
|
19
20
|
route: request.route.path,
|
|
20
|
-
http_method: request.request_method
|
|
21
|
-
ip: request.client_ip
|
|
21
|
+
http_method: request.request_method
|
|
22
22
|
)
|
|
23
|
-
|
|
23
|
+
@zen.track_request(request)
|
|
24
24
|
|
|
25
|
-
if
|
|
26
|
-
|
|
25
|
+
if @zen.config.collect_api_schema?
|
|
26
|
+
@zen.track_discovered_route(request)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
@@ -128,8 +128,8 @@ module Aikido::Zen
|
|
|
128
128
|
# @param status_code [Integer]
|
|
129
129
|
# @param route [String]
|
|
130
130
|
# @param http_method [String]
|
|
131
|
-
def track?(status_code:, route:, http_method
|
|
132
|
-
return false if @
|
|
131
|
+
def track?(status_code:, route:, http_method:)
|
|
132
|
+
return false if @zen.request_bypassed?
|
|
133
133
|
|
|
134
134
|
# In the UI we want to show only successful (2xx) or redirect (3xx) responses
|
|
135
135
|
# anything else is discarded.
|
|
@@ -13,7 +13,7 @@ module Aikido::Zen
|
|
|
13
13
|
def call(env)
|
|
14
14
|
request = Aikido::Zen::Middleware.request_from(env)
|
|
15
15
|
|
|
16
|
-
return @app.call(env) if
|
|
16
|
+
return @app.call(env) if @zen.request_bypassed?
|
|
17
17
|
|
|
18
18
|
user_agent = request.user_agent
|
|
19
19
|
|
|
@@ -31,10 +31,6 @@ module Aikido::Zen
|
|
|
31
31
|
|
|
32
32
|
@app.call(env)
|
|
33
33
|
end
|
|
34
|
-
|
|
35
|
-
def bypassed?(request)
|
|
36
|
-
@settings.bypassed_ips.include?(request.client_ip)
|
|
37
|
-
end
|
|
38
34
|
end
|
|
39
35
|
end
|
|
40
36
|
end
|
|
@@ -30,7 +30,7 @@ module Aikido::Zen
|
|
|
30
30
|
|
|
31
31
|
request = context.request
|
|
32
32
|
|
|
33
|
-
return false if @
|
|
33
|
+
return false if @zen.request_bypassed?
|
|
34
34
|
|
|
35
35
|
if should_block_user?(request)
|
|
36
36
|
status, headers, body = @config.blocked_responder.call(request, :user)
|
|
@@ -52,9 +52,7 @@ module Aikido::Zen
|
|
|
52
52
|
|
|
53
53
|
settings = Aikido::Zen.runtime_settings
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
unless settings.bypassed_ip?(client_ip)
|
|
55
|
+
unless Aikido::Zen.request_bypassed?
|
|
58
56
|
Aikido::Zen.track_outbound(connection)
|
|
59
57
|
|
|
60
58
|
if settings.block_outbound?(connection)
|
|
@@ -64,9 +64,7 @@ module Aikido::Zen
|
|
|
64
64
|
|
|
65
65
|
settings = Aikido::Zen.runtime_settings
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
unless settings.bypassed_ip?(client_ip)
|
|
67
|
+
unless Aikido::Zen.request_bypassed?
|
|
70
68
|
Aikido::Zen.track_outbound(connection)
|
|
71
69
|
|
|
72
70
|
if settings.block_outbound?(connection)
|
|
@@ -50,9 +50,7 @@ module Aikido::Zen
|
|
|
50
50
|
|
|
51
51
|
settings = Aikido::Zen.runtime_settings
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
unless settings.bypassed_ip?(client_ip)
|
|
53
|
+
unless Aikido::Zen.request_bypassed?
|
|
56
54
|
Aikido::Zen.track_outbound(connection)
|
|
57
55
|
|
|
58
56
|
if settings.block_outbound?(connection)
|
|
@@ -56,9 +56,7 @@ module Aikido::Zen
|
|
|
56
56
|
|
|
57
57
|
settings = Aikido::Zen.runtime_settings
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
unless settings.bypassed_ip?(client_ip)
|
|
59
|
+
unless Aikido::Zen.request_bypassed?
|
|
62
60
|
Aikido::Zen.track_outbound(connection)
|
|
63
61
|
|
|
64
62
|
if settings.block_outbound?(connection)
|
|
@@ -70,9 +70,7 @@ module Aikido::Zen
|
|
|
70
70
|
|
|
71
71
|
settings = Aikido::Zen.runtime_settings
|
|
72
72
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
unless settings.bypassed_ip?(client_ip)
|
|
73
|
+
unless Aikido::Zen.request_bypassed?
|
|
76
74
|
Aikido::Zen.track_outbound(connection)
|
|
77
75
|
|
|
78
76
|
if settings.block_outbound?(connection)
|
|
@@ -50,9 +50,7 @@ module Aikido::Zen
|
|
|
50
50
|
|
|
51
51
|
settings = Aikido::Zen.runtime_settings
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
unless settings.bypassed_ip?(client_ip)
|
|
53
|
+
unless Aikido::Zen.request_bypassed?
|
|
56
54
|
Aikido::Zen.track_outbound(connection)
|
|
57
55
|
|
|
58
56
|
if settings.block_outbound?(connection)
|
|
@@ -55,9 +55,7 @@ module Aikido::Zen
|
|
|
55
55
|
|
|
56
56
|
settings = Aikido::Zen.runtime_settings
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
unless settings.bypassed_ip?(client_ip)
|
|
58
|
+
unless Aikido::Zen.request_bypassed?
|
|
61
59
|
Aikido::Zen.track_outbound(connection)
|
|
62
60
|
|
|
63
61
|
if settings.block_outbound?(connection)
|
|
@@ -86,9 +86,7 @@ module Aikido::Zen
|
|
|
86
86
|
|
|
87
87
|
settings = Aikido::Zen.runtime_settings
|
|
88
88
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
unless settings.bypassed_ip?(client_ip)
|
|
89
|
+
unless Aikido::Zen.request_bypassed?
|
|
92
90
|
Aikido::Zen.track_outbound(connection)
|
|
93
91
|
|
|
94
92
|
if settings.block_outbound?(connection)
|
|
@@ -59,9 +59,7 @@ module Aikido::Zen
|
|
|
59
59
|
|
|
60
60
|
settings = Aikido::Zen.runtime_settings
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
unless settings.bypassed_ip?(client_ip)
|
|
62
|
+
unless Aikido::Zen.request_bypassed?
|
|
65
63
|
Aikido::Zen.track_outbound(connection)
|
|
66
64
|
|
|
67
65
|
if settings.block_outbound?(connection)
|
|
@@ -26,9 +26,7 @@ module Aikido::Zen
|
|
|
26
26
|
|
|
27
27
|
settings = Aikido::Zen.runtime_settings
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
unless settings.bypassed_ip?(client_ip)
|
|
29
|
+
unless Aikido::Zen.request_bypassed?
|
|
32
30
|
Aikido::Zen.track_outbound(connection)
|
|
33
31
|
|
|
34
32
|
if settings.block_outbound?(connection)
|
data/lib/aikido/zen/version.rb
CHANGED
data/lib/aikido/zen.rb
CHANGED
|
@@ -153,6 +153,23 @@ module Aikido
|
|
|
153
153
|
Fiber.current.aikido_current_context = context
|
|
154
154
|
end
|
|
155
155
|
|
|
156
|
+
# @return [Boolean] whether the current request is bypassed.
|
|
157
|
+
def self.request_bypassed?
|
|
158
|
+
context = current_context
|
|
159
|
+
return unless context
|
|
160
|
+
|
|
161
|
+
return context.request_bypassed unless context.request_bypassed.nil?
|
|
162
|
+
|
|
163
|
+
context.request_bypassed = runtime_settings.bypassed_ip?(context.request.client_ip)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# Marks the current request as bypassed.
|
|
167
|
+
#
|
|
168
|
+
# @return [void]
|
|
169
|
+
def self.request_bypassed!
|
|
170
|
+
current_context&.request_bypassed = true
|
|
171
|
+
end
|
|
172
|
+
|
|
156
173
|
# Track statistics about an HTTP request the app is handling.
|
|
157
174
|
#
|
|
158
175
|
# @param request [Aikido::Zen::Request]
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: aikido-zen
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.7.2
|
|
4
|
+
version: 1.7.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Aikido Security
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: concurrent-ruby
|
|
@@ -93,6 +93,7 @@ files:
|
|
|
93
93
|
- docs/invalid-sql-queries.md
|
|
94
94
|
- docs/proxy.md
|
|
95
95
|
- docs/rails.md
|
|
96
|
+
- docs/request-bypassing.md
|
|
96
97
|
- docs/troubleshooting.md
|
|
97
98
|
- lib/aikido-zen.rb
|
|
98
99
|
- lib/aikido/zen.rb
|