aikido-zen 1.0.0.pre.beta.1-x86_64-mingw-64 → 1.0.1.beta.2-x86_64-mingw-64
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/.aikido +6 -0
- data/README.md +67 -83
- data/lib/aikido/zen/config.rb +11 -2
- data/lib/aikido/zen/context.rb +4 -0
- data/lib/aikido/zen/internals.rb +41 -7
- data/lib/aikido/zen/libzen-v0.1.39-x86_64-mingw-64.dll +0 -0
- data/lib/aikido/zen/middleware/request_tracker.rb +6 -4
- data/lib/aikido/zen/rails_engine.rb +5 -9
- data/lib/aikido/zen/request/heuristic_router.rb +6 -0
- data/lib/aikido/zen/sink.rb +5 -0
- data/lib/aikido/zen/sinks/async_http.rb +35 -16
- data/lib/aikido/zen/sinks/curb.rb +52 -26
- data/lib/aikido/zen/sinks/em_http.rb +39 -25
- data/lib/aikido/zen/sinks/excon.rb +63 -45
- data/lib/aikido/zen/sinks/file.rb +67 -71
- data/lib/aikido/zen/sinks/http.rb +38 -19
- data/lib/aikido/zen/sinks/httpclient.rb +51 -22
- data/lib/aikido/zen/sinks/httpx.rb +37 -18
- data/lib/aikido/zen/sinks/kernel.rb +18 -57
- data/lib/aikido/zen/sinks/mysql2.rb +19 -7
- data/lib/aikido/zen/sinks/net_http.rb +37 -19
- data/lib/aikido/zen/sinks/patron.rb +41 -24
- data/lib/aikido/zen/sinks/pg.rb +50 -27
- data/lib/aikido/zen/sinks/resolv.rb +37 -16
- data/lib/aikido/zen/sinks/socket.rb +33 -17
- data/lib/aikido/zen/sinks/sqlite3.rb +31 -12
- data/lib/aikido/zen/sinks/trilogy.rb +19 -7
- data/lib/aikido/zen/sinks.rb +29 -20
- data/lib/aikido/zen/sinks_dsl.rb +226 -0
- data/lib/aikido/zen/version.rb +2 -2
- data/lib/aikido/zen.rb +18 -1
- data/placeholder/.gitignore +4 -0
- data/placeholder/README.md +11 -0
- data/placeholder/Rakefile +75 -0
- data/placeholder/lib/placeholder.rb.template +3 -0
- data/placeholder/placeholder.gemspec.template +20 -0
- data/tasklib/libzen.rake +70 -66
- metadata +17 -13
- data/CHANGELOG.md +0 -25
- data/lib/aikido/zen/libzen-v0.1.37.x86_64.dll +0 -0
- data/lib/aikido.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6870d1d0a0a5f98ddaa519ea4d4629d5f188651767d14e7d73e7f8f5f768dce5
|
4
|
+
data.tar.gz: 8fe0c47688f64f8a735b192159339ff19499f4da99451045ad0e3fad95bccdde
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 516d0a01b52bc249bb5ed730322442c6885e76beb561b49e2dfac7dae399952ba55d7a9485c2f14ff17cdeea2e71ffdd4df94d25d106039aa4114f4327287d45
|
7
|
+
data.tar.gz: 3eb82a1a977b37c4cfba905a22ab071fd1f3ca68529c282b7ddb70659f6b52acefeba80d25d95d72db48bff6ce0dc43dc45e03cb04d691ec09781d4c237da64b
|
data/.aikido
ADDED
data/README.md
CHANGED
@@ -1,146 +1,137 @@
|
|
1
1
|

|
2
2
|
|
3
|
+
# Zen, in-app firewall for Ruby | by Aikido
|
4
|
+
|
3
5
|
[](https://badge.fury.io/rb/aikido-zen)
|
4
6
|
[](http://makeapullrequest.com)
|
5
7
|
[](https://github.com/AikidoSec/firewall-ruby/actions/workflows/main.yml)
|
6
8
|
[](https://github.com/AikidoSec/firewall-ruby/actions/workflows/release.yml)
|
7
9
|
|
8
|
-
|
10
|
+
Zen, your in-app firewall for peace of mind - at runtime.
|
11
|
+
|
12
|
+
Zen by Aikido is an embedded Web Application Firewall that autonomously protects Ruby apps against common and critical attacks.
|
9
13
|
|
10
|
-
|
14
|
+
It protects your Ruby apps by preventing user input containing dangerous strings, which allow injection, pollution, and path traversal attacks. It runs on the same server as your Ruby app for simple [installation](#installation) and zero maintenance.
|
11
15
|
|
12
|
-
|
13
|
-
Ruby on Rails apps against common and critical attacks.
|
16
|
+
## Features
|
14
17
|
|
15
|
-
|
16
|
-
strings, preventing SQL injection and SSRF attacks. It runs embedded on your
|
17
|
-
Rails application, for simple installation and zero maintenance.
|
18
|
+
Zen will autonomously protect your Ruby applications against:
|
18
19
|
|
19
20
|
* 🛡️ [SQL injection attacks](https://www.aikido.dev/blog/the-state-of-sql-injections)
|
20
21
|
* 🛡️ [Server-side request forgery (SSRF)](https://github.com/AikidoSec/firewall-node/blob/main/docs/ssrf.md)
|
21
|
-
* 🛡️ [Command injection attacks](https://www.aikido.dev/blog/command-injection-in-2024-unpacked)
|
22
|
-
* 🛡️ [Path traversal attacks](https://www.aikido.dev/blog/path-traversal-in-2024-the-year-unpacked)
|
22
|
+
* 🛡️ [Command injection attacks](https://www.aikido.dev/blog/command-injection-in-2024-unpacked)
|
23
|
+
* 🛡️ [Path traversal attacks](https://www.aikido.dev/blog/path-traversal-in-2024-the-year-unpacked)
|
23
24
|
* 🛡️ [NoSQL injection attacks](https://www.aikido.dev/blog/web-application-security-vulnerabilities) (coming soon)
|
24
25
|
|
25
|
-
Zen operates autonomously on the same server as your
|
26
|
+
Zen operates autonomously on the same server as your Ruby app to:
|
26
27
|
|
27
|
-
* ✅ Secure your app like a classic web application firewall (WAF), but with none of the infrastructure or cost
|
28
|
-
* ✅ Rate limit specific API endpoints by IP or by user
|
29
|
-
* ✅ Allow you to block specific users manually
|
28
|
+
* ✅ Secure your app like a classic web application firewall (WAF), but with none of the infrastructure or cost
|
29
|
+
* ✅ Rate limit specific API endpoints by IP or by user
|
30
|
+
* ✅ Allow you to block specific users manually
|
30
31
|
|
31
32
|
## Supported libraries and frameworks
|
32
33
|
|
33
34
|
Zen for Ruby 2.7+ is compatible with:
|
34
35
|
|
36
|
+
### Web frameworks
|
37
|
+
|
38
|
+
* ✅ [Ruby on Rails](docs/rails.md) 7.x, 8.x
|
39
|
+
|
35
40
|
### Database drivers
|
36
41
|
|
37
|
-
* ✅ [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) 1.x, 2.x
|
38
|
-
* ✅ [pg](https://github.com/ged/ruby-pg) 1.x
|
39
|
-
* ✅ [
|
40
|
-
* ✅ [
|
42
|
+
* ✅ [`sqlite3`](https://github.com/sparklemotion/sqlite3-ruby) 1.x, 2.x
|
43
|
+
* ✅ [`pg`](https://github.com/ged/ruby-pg) 1.x
|
44
|
+
* ✅ [`mysql2`](https://github.com/brianmario/mysql2) 0.x
|
45
|
+
* ✅ [`trilogy`](https://github.com/trilogy-libraries/trilogy) 2.x
|
41
46
|
|
42
|
-
### ORMs and
|
47
|
+
### ORMs and query builders
|
43
48
|
|
44
49
|
See list above for supported database drivers.
|
45
50
|
|
46
51
|
* ✅ [ActiveRecord](https://github.com/rails/rails)
|
47
52
|
* ✅ [Sequel](https://github.com/jeremyevans/sequel)
|
48
53
|
|
49
|
-
### HTTP
|
54
|
+
### HTTP clients
|
50
55
|
|
51
|
-
* ✅ [net-http](https://github.com/ruby/net-http)
|
52
|
-
* ✅ [http.rb](https://github.com/httprb/http) 1.x, 2.x, 3.x, 4.x, 5.x
|
53
|
-
* ✅ [httpx](https://gitlab.com/os85/httpx) 1.x (1.1.3+)
|
54
|
-
* ✅ [
|
55
|
-
* ✅ [excon](https://github.com/excon/excon) 0.x (0.50.0+), 1.x
|
56
|
-
* ✅ [
|
57
|
-
* ✅ [
|
58
|
-
* ✅ [
|
59
|
-
* ✅ [
|
60
|
-
* ✅ [
|
56
|
+
* ✅ [`net-http`](https://github.com/ruby/net-http)
|
57
|
+
* ✅ [`http.rb`](https://github.com/httprb/http) 1.x, 2.x, 3.x, 4.x, 5.x
|
58
|
+
* ✅ [`httpx`](https://gitlab.com/os85/httpx) 1.x (1.1.3+)
|
59
|
+
* ✅ [`httpclient`](https://github.com/nahi/httpclient) 2.x, 3.x
|
60
|
+
* ✅ [`excon`](https://github.com/excon/excon) 0.x (0.50.0+), 1.x
|
61
|
+
* ✅ [`curb`](https://github.com/taf2/curb) 0.x (0.2.3+), 1.x
|
62
|
+
* ✅ [`patron`](https://github.com/toland/patron) 0.x (0.6.4+)
|
63
|
+
* ✅ [`typhoeus`](https://github.com/typhoeus/typhoeus) 0.x (0.5.0+), 1.x
|
64
|
+
* ✅ [`async-http`](https://github.com/igrigorik/em-http-request) 0.x (0.70.0+)
|
65
|
+
* ✅ [`em-http-request`](https://github.com/igrigorik/em-http-request) 1.x
|
61
66
|
|
62
67
|
## Installation
|
63
68
|
|
64
69
|
We recommend testing Zen locally or on staging before deploying to production.
|
65
70
|
|
66
|
-
```
|
71
|
+
```sh
|
67
72
|
bundle add aikido-zen
|
68
73
|
```
|
69
74
|
|
70
75
|
or, if not using bundler:
|
71
76
|
|
72
|
-
```
|
77
|
+
```sh
|
73
78
|
gem install aikido-zen
|
74
79
|
```
|
75
80
|
|
76
81
|
For framework specific instructions, check out our docs:
|
77
82
|
|
78
|
-
* [Ruby on Rails
|
83
|
+
* [Ruby on Rails](docs/rails.md)
|
79
84
|
|
80
|
-
##
|
85
|
+
## Reporting to your Aikido Security dashboard
|
81
86
|
|
82
|
-
|
87
|
+
> Aikido is your no nonsense application security platform. One central system that scans your source code & cloud, shows you what vulnerabilities matter, and how to fix them - fast. So you can get back to building.
|
83
88
|
|
84
|
-
|
89
|
+
Zen is a new product by Aikido. Built for developers to level up their security. While Aikido scans, get Zen for always-on protection.
|
85
90
|
|
86
|
-
|
87
|
-
how to send events to Aikido.
|
91
|
+
You can use some of Zen's features without Aikido, of course. Peace of mind is just a few lines of code away.
|
88
92
|
|
89
|
-
|
93
|
+
But you will get the most value by reporting your data to Aikido.
|
90
94
|
|
91
|
-
|
95
|
+
You will need an Aikido account and a token to report events to Aikido. If you don't have an account, you can [sign up for free](https://app.aikido.dev/login).
|
92
96
|
|
93
|
-
|
97
|
+
Here's how:
|
94
98
|
|
95
|
-
|
96
|
-
|
97
|
-
|
99
|
+
* [Log in to your Aikido account](https://app.aikido.dev/login).
|
100
|
+
* Go to [Zen](https://app.aikido.dev/runtime/services).
|
101
|
+
* Go to apps.
|
102
|
+
* Click on **Add app**.
|
103
|
+
* Choose a name for your app.
|
104
|
+
* Click **Generate token**.
|
105
|
+
* Copy the token.
|
106
|
+
* Set the token as an environment variable, `AIKIDO_TOKEN`, using [dotenv](https://github.com/bkeepers/dotenv) or another method of your choosing.
|
98
107
|
|
99
|
-
|
100
|
-
While Aikido scans, get Zen for always-on protection.
|
108
|
+
## Running in production (blocking) mode
|
101
109
|
|
102
|
-
|
103
|
-
just a few lines of code away.
|
110
|
+
By default, Zen will only detect and report attacks to Aikido.
|
104
111
|
|
105
|
-
|
112
|
+
To block requests, set the `AIKIDO_BLOCK` environment variable to `true`.
|
106
113
|
|
107
|
-
|
108
|
-
don't have an account, you can sign up for free.
|
114
|
+
See [Reporting to Aikido](#reporting-to-your-aikido-security-dashboard) to learn how to send events to Aikido.
|
109
115
|
|
110
|
-
|
116
|
+
## Additional configuration
|
111
117
|
|
112
|
-
|
113
|
-
* Go to "Zen" on the sidebar.
|
114
|
-
* Click on "Add App".
|
115
|
-
* Choose a name for your App.
|
116
|
-
* Click "Continue to Install"
|
117
|
-
* Click "Generate Token".
|
118
|
-
* Copy the token.
|
119
|
-
* Set the token as an environment variable, `AIKIDO_TOKEN`, using
|
120
|
-
[dotenv](https://github.com/bkeepers/dotenv) or another method
|
121
|
-
of your choosing.
|
118
|
+
[Configure Zen using environment variables for authentication, mode settings, debugging, and more.](https://help.aikido.dev/doc/configuration-via-env-vars/docrSItUkeR9)
|
122
119
|
|
123
|
-
##
|
120
|
+
## License
|
124
121
|
|
125
|
-
|
126
|
-
application's performance.
|
122
|
+
This program is offered under a commercial and under the AGPL license. You can be released from the requirements of the AGPL license by purchasing a commercial license. Buying such a license is mandatory as soon as you develop commercial activities involving the Zen software without disclosing the source code of your own applications.
|
127
123
|
|
128
|
-
For
|
129
|
-
endpoint that performs a single SQL SELECT query:
|
124
|
+
For more information, please contact Aikido Security at this address: support@aikido.dev or create an account at https://app.aikido.dev.
|
130
125
|
|
131
|
-
|
132
|
-
|------------------|---------------|---------------|
|
133
|
-
| 3.527ms | 3.583ms | +0.056ms |
|
126
|
+
## Benchmarks
|
134
127
|
|
135
|
-
|
136
|
-
will vary based on hardware.
|
128
|
+
We run a benchmark on every commit to ensure Zen has a minimal impact on your application's performance.
|
137
129
|
|
138
|
-
See [benchmarks](benchmarks)
|
130
|
+
See [benchmarks](benchmarks)
|
139
131
|
|
140
132
|
## Bug bounty program
|
141
133
|
|
142
|
-
Our bug bounty program is public and can be found by all registered Intigriti
|
143
|
-
users at: https://app.intigriti.com/researcher/programs/aikido/aikidoruntime
|
134
|
+
Our bug bounty program is public and can be found by all registered Intigriti users at: https://app.intigriti.com/researcher/programs/aikido/aikidozenbeta
|
144
135
|
|
145
136
|
## Contributing
|
146
137
|
|
@@ -150,13 +141,6 @@ See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for more information.
|
|
150
141
|
|
151
142
|
See [CODE_OF_CONDUCT.md](.github/CODE_OF_CONDUCT.md) for more information.
|
152
143
|
|
153
|
-
##
|
154
|
-
|
155
|
-
This program is offered under a commercial and under the AGPL license. You can
|
156
|
-
be released from the requirements of the AGPL license by purchasing a commercial
|
157
|
-
license. Buying such a license is mandatory as soon as you develop commercial
|
158
|
-
activities involving the Zen software without disclosing the source code of your
|
159
|
-
own applications.
|
144
|
+
## Security
|
160
145
|
|
161
|
-
|
162
|
-
support@aikido.dev or create an account at https://app.aikido.dev.
|
146
|
+
See [SECURITY.md](.github/SECURITY.md) for more information.
|
data/lib/aikido/zen/config.rb
CHANGED
@@ -8,6 +8,12 @@ require_relative "context"
|
|
8
8
|
|
9
9
|
module Aikido::Zen
|
10
10
|
class Config
|
11
|
+
# @api private
|
12
|
+
# @return [Boolean] whether Aikido should protect.
|
13
|
+
def protect?
|
14
|
+
!api_token.nil? || blocking_mode? || debugging?
|
15
|
+
end
|
16
|
+
|
11
17
|
# @return [Boolean] whether Aikido should be turned completely off (no
|
12
18
|
# intercepting calls to protect the app, no agent process running, no
|
13
19
|
# middleware installed). Defaults to false (so, enabled). Can be set
|
@@ -57,7 +63,7 @@ module Aikido::Zen
|
|
57
63
|
|
58
64
|
# @return [string] Path of the socket where the detached agent will listen.
|
59
65
|
# By default, is stored under the root application path with file name
|
60
|
-
# `aikido-detached-agent.
|
66
|
+
# `aikido-detached-agent.sock`
|
61
67
|
attr_reader :detached_agent_socket_path
|
62
68
|
|
63
69
|
# @return [Boolean] is the agent in debugging mode?
|
@@ -158,7 +164,7 @@ module Aikido::Zen
|
|
158
164
|
self.debugging = read_boolean_from_env(ENV.fetch("AIKIDO_DEBUG", false))
|
159
165
|
self.logger = Logger.new($stdout, progname: "aikido", level: debugging ? Logger::DEBUG : Logger::INFO)
|
160
166
|
self.max_performance_samples = 5000
|
161
|
-
self.detached_agent_socket_path =
|
167
|
+
self.detached_agent_socket_path = ENV.fetch("AIKIDO_DETACHED_AGENT_SOCKET_PATH", DEFAULT_DETACHED_AGENT_SOCKET_PATH)
|
162
168
|
self.max_compressed_stats = 100
|
163
169
|
self.max_outbound_connections = 200
|
164
170
|
self.max_users_tracked = 1000
|
@@ -246,6 +252,9 @@ module Aikido::Zen
|
|
246
252
|
# @!visibility private
|
247
253
|
DEFAULT_JSON_DECODER = JSON.method(:parse)
|
248
254
|
|
255
|
+
# @!visibility private
|
256
|
+
DEFAULT_DETACHED_AGENT_SOCKET_PATH = "aikido-detached-agent.sock"
|
257
|
+
|
249
258
|
# @!visibility private
|
250
259
|
DEFAULT_BLOCKED_RESPONDER = ->(request, blocking_type) do
|
251
260
|
message = case blocking_type
|
data/lib/aikido/zen/context.rb
CHANGED
@@ -20,6 +20,9 @@ module Aikido::Zen
|
|
20
20
|
# @return [Aikido::Zen::Request]
|
21
21
|
attr_reader :request
|
22
22
|
|
23
|
+
# @return [Boolean]
|
24
|
+
attr_accessor :scanning
|
25
|
+
|
23
26
|
# @param request [Rack::Request] a Request object that implements the
|
24
27
|
# Rack::Request API, to which we will delegate behavior.
|
25
28
|
# @param settings [Aikido::Zen::RuntimeSettings]
|
@@ -32,6 +35,7 @@ module Aikido::Zen
|
|
32
35
|
@settings = settings
|
33
36
|
@payload_sources = sources
|
34
37
|
@metadata = {}
|
38
|
+
@scanning = false
|
35
39
|
end
|
36
40
|
|
37
41
|
# Fetch some metadata stored in the Context.
|
data/lib/aikido/zen/internals.rb
CHANGED
@@ -13,14 +13,48 @@ module Aikido::Zen
|
|
13
13
|
attr_accessor :libzen_name
|
14
14
|
end
|
15
15
|
|
16
|
-
self.
|
17
|
-
"libzen-v#{LIBZEN_VERSION}"
|
18
|
-
FFI::Platform::
|
19
|
-
|
20
|
-
|
16
|
+
def self.libzen_names
|
17
|
+
lib_name = "libzen-v#{LIBZEN_VERSION}"
|
18
|
+
lib_ext = FFI::Platform::LIBSUFFIX
|
19
|
+
|
20
|
+
# Gem::Platform#version should be understood as an arbitrary Ruby defined
|
21
|
+
# OS specific string. A platform with a version string is considered more
|
22
|
+
# specific than a platform without a version string.
|
23
|
+
# https://docs.ruby-lang.org/en/3.3/Gem/Platform.html
|
24
|
+
|
25
|
+
platform = Gem::Platform.local.dup
|
26
|
+
|
27
|
+
# Library names in preferred order.
|
28
|
+
#
|
29
|
+
# If two library names are added, the specific platform library names is
|
30
|
+
# first and the generic platform library name is second.
|
31
|
+
names = []
|
32
|
+
|
33
|
+
names << "#{lib_name}-#{platform}.#{lib_ext}"
|
34
|
+
|
35
|
+
unless platform.version.nil?
|
36
|
+
platform.version = nil
|
37
|
+
names << "#{lib_name}-#{platform}.#{lib_ext}"
|
38
|
+
end
|
39
|
+
|
40
|
+
names
|
41
|
+
end
|
42
|
+
|
43
|
+
# Load the most specific library
|
44
|
+
def self.load_libzen
|
45
|
+
libzen_names.each do |libzen_name|
|
46
|
+
libzen_path = File.expand_path(libzen_name, __dir__)
|
47
|
+
begin
|
48
|
+
return ffi_lib(libzen_path)
|
49
|
+
rescue LoadError
|
50
|
+
# empty
|
51
|
+
end
|
52
|
+
end
|
53
|
+
raise LoadError, "Could not load libzen"
|
54
|
+
end
|
21
55
|
|
22
56
|
begin
|
23
|
-
|
57
|
+
load_libzen
|
24
58
|
|
25
59
|
# @!method self.detect_sql_injection_native(query, input, dialect)
|
26
60
|
# @param (see .detect_sql_injection)
|
@@ -30,7 +64,7 @@ module Aikido::Zen
|
|
30
64
|
# calling libzen.
|
31
65
|
attach_function :detect_sql_injection_native, :detect_sql_injection,
|
32
66
|
[:string, :string, :int], :int
|
33
|
-
rescue LoadError, FFI::NotFoundError => err
|
67
|
+
rescue LoadError, FFI::NotFoundError => err # rubocop:disable Lint/ShadowedException
|
34
68
|
# :nocov:
|
35
69
|
|
36
70
|
# Emit an $stderr warning at startup.
|
Binary file
|
@@ -13,14 +13,16 @@ module Aikido::Zen
|
|
13
13
|
request = Aikido::Zen::Middleware.request_from(env)
|
14
14
|
response = @app.call(env)
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
if Aikido::Zen.config.collect_api_schema? && request.route && track?(
|
16
|
+
if request.route && track?(
|
19
17
|
status_code: response[0],
|
20
18
|
route: request.route.path,
|
21
19
|
http_method: request.request_method
|
22
20
|
)
|
23
|
-
Aikido::Zen.
|
21
|
+
Aikido::Zen.track_request request
|
22
|
+
|
23
|
+
if Aikido::Zen.config.collect_api_schema?
|
24
|
+
Aikido::Zen.track_discovered_route(request)
|
25
|
+
end
|
24
26
|
end
|
25
27
|
|
26
28
|
response
|
@@ -10,7 +10,7 @@ module Aikido::Zen
|
|
10
10
|
end
|
11
11
|
|
12
12
|
initializer "aikido.add_middleware" do |app|
|
13
|
-
next
|
13
|
+
next unless config.zen.protect?
|
14
14
|
|
15
15
|
app.middleware.use Aikido::Zen::Middleware::SetContext
|
16
16
|
app.middleware.use Aikido::Zen::Middleware::CheckAllowedAddresses
|
@@ -33,9 +33,9 @@ module Aikido::Zen
|
|
33
33
|
initializer "aikido.configuration" do |app|
|
34
34
|
# Allow the logger to be configured before checking if disabled? so we can
|
35
35
|
# let the user know that the agent is disabled.
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
logger = ::Rails.logger
|
37
|
+
logger = ActiveSupport::TaggedLogging.new(logger) unless logger.respond_to?(:tagged)
|
38
|
+
app.config.zen.logger = logger.tagged("aikido")
|
39
39
|
|
40
40
|
app.config.zen.request_builder = Aikido::Zen::Context::RAILS_REQUEST_BUILDER
|
41
41
|
|
@@ -51,10 +51,7 @@ module Aikido::Zen
|
|
51
51
|
end
|
52
52
|
|
53
53
|
config.after_initialize do
|
54
|
-
|
55
|
-
config.zen.logger.warn("Zen has been disabled and will not run.")
|
56
|
-
next
|
57
|
-
end
|
54
|
+
next unless config.zen.protect?
|
58
55
|
|
59
56
|
# Make sure this is run at the end of the initialization process, so
|
60
57
|
# that any gems required after aikido-zen are detected and patched
|
@@ -63,7 +60,6 @@ module Aikido::Zen
|
|
63
60
|
|
64
61
|
# It's important we start after loading sinks, so we can report the installed packages
|
65
62
|
Aikido::Zen.start!
|
66
|
-
Aikido::Zen.start!
|
67
63
|
|
68
64
|
# Agent's bootstrap process has finished —Controllers are patched to block
|
69
65
|
# unwanted requests, sinks are loaded, scanners are running—, so we mark
|
@@ -30,6 +30,10 @@ module Aikido::Zen
|
|
30
30
|
|
31
31
|
private def parameterize_segment(segment)
|
32
32
|
case segment
|
33
|
+
when ULID
|
34
|
+
":ulid"
|
35
|
+
when OBJECT_ID
|
36
|
+
":objectId"
|
33
37
|
when NUMBER
|
34
38
|
":number"
|
35
39
|
when UUID
|
@@ -57,6 +61,8 @@ module Aikido::Zen
|
|
57
61
|
| 00000000-0000-0000-0000-000000000000
|
58
62
|
| ffffffff-ffff-ffff-ffff-ffffffffffff
|
59
63
|
)\z/ix
|
64
|
+
ULID = /\A[0-9A-HJKMNP-TV-Z]{26}\z/i
|
65
|
+
OBJECT_ID = /\A[0-9a-f]{24}\z/i
|
60
66
|
EMAIL = /\A
|
61
67
|
[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+
|
62
68
|
@
|
data/lib/aikido/zen/sink.rb
CHANGED
@@ -80,6 +80,9 @@ module Aikido::Zen
|
|
80
80
|
# @raise [Aikido::UnderAttackError] if an attack is detected and
|
81
81
|
# blocking_mode is enabled.
|
82
82
|
def scan(context: Aikido::Zen.current_context, **scan_params)
|
83
|
+
return if context&.scanning
|
84
|
+
context&.scanning = true
|
85
|
+
|
83
86
|
return if context&.protection_disabled?
|
84
87
|
|
85
88
|
scan = Scan.new(sink: self, context: context)
|
@@ -108,6 +111,8 @@ module Aikido::Zen
|
|
108
111
|
@reporter.call(scan) if scans_performed > 0
|
109
112
|
|
110
113
|
scan
|
114
|
+
ensure
|
115
|
+
context&.scanning = false
|
111
116
|
end
|
112
117
|
end
|
113
118
|
end
|
@@ -1,26 +1,46 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "../
|
3
|
+
require_relative "../scanners/ssrf_scanner"
|
4
4
|
require_relative "../outbound_connection_monitor"
|
5
5
|
|
6
6
|
module Aikido::Zen
|
7
7
|
module Sinks
|
8
8
|
module Async
|
9
9
|
module HTTP
|
10
|
+
def self.load_sinks!
|
11
|
+
if Gem.loaded_specs["async-http"]
|
12
|
+
require "async/http"
|
13
|
+
|
14
|
+
::Async::HTTP::Client.prepend(Async::HTTP::ClientExtensions)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
10
18
|
SINK = Sinks.add("async-http", scanners: [
|
11
|
-
|
12
|
-
|
19
|
+
Scanners::SSRFScanner,
|
20
|
+
OutboundConnectionMonitor
|
13
21
|
])
|
14
22
|
|
15
|
-
module
|
16
|
-
def
|
23
|
+
module Helpers
|
24
|
+
def self.scan(request, connection, operation)
|
25
|
+
SINK.scan(
|
26
|
+
request: request,
|
27
|
+
connection: connection,
|
28
|
+
operation: operation
|
29
|
+
)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClientExtensions
|
34
|
+
extend Sinks::DSL
|
35
|
+
|
36
|
+
sink_around :call do |super_call, request|
|
17
37
|
uri = URI(format("%<scheme>s://%<authority>s%<path>s", {
|
18
38
|
scheme: request.scheme || scheme,
|
19
39
|
authority: request.authority || authority,
|
20
40
|
path: request.path
|
21
41
|
}))
|
22
42
|
|
23
|
-
wrapped_request =
|
43
|
+
wrapped_request = Scanners::SSRFScanner::Request.new(
|
24
44
|
verb: request.method,
|
25
45
|
uri: uri,
|
26
46
|
headers: request.headers.to_h,
|
@@ -28,22 +48,21 @@ module Aikido::Zen
|
|
28
48
|
)
|
29
49
|
|
30
50
|
# Store the request information so the DNS sinks can pick it up.
|
31
|
-
|
51
|
+
context = Aikido::Zen.current_context
|
52
|
+
if context
|
32
53
|
prev_request = context["ssrf.request"]
|
33
54
|
context["ssrf.request"] = wrapped_request
|
34
55
|
end
|
35
56
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
operation: "request"
|
40
|
-
)
|
57
|
+
connection = OutboundConnection.from_uri(uri)
|
58
|
+
|
59
|
+
Helpers.scan(wrapped_request, connection, "request")
|
41
60
|
|
42
|
-
response =
|
61
|
+
response = super_call.call
|
43
62
|
|
44
|
-
|
63
|
+
Scanners::SSRFScanner.track_redirects(
|
45
64
|
request: wrapped_request,
|
46
|
-
response:
|
65
|
+
response: Scanners::SSRFScanner::Response.new(
|
47
66
|
status: response.status,
|
48
67
|
headers: response.headers.to_h,
|
49
68
|
header_normalizer: ->(value) { Array(value).join(", ") }
|
@@ -60,4 +79,4 @@ module Aikido::Zen
|
|
60
79
|
end
|
61
80
|
end
|
62
81
|
|
63
|
-
|
82
|
+
Aikido::Zen::Sinks::Async::HTTP.load_sinks!
|