aikido-zen 0.1.0.alpha4-x86_64-darwin → 0.1.1-x86_64-darwin
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.simplecov +19 -0
- data/CHANGELOG.md +16 -0
- data/README.md +136 -23
- data/Rakefile +4 -0
- data/benchmarks/README.md +27 -0
- data/benchmarks/rails7.1_sql_injection.js +74 -0
- data/docs/banner.svg +203 -0
- data/docs/config.md +123 -0
- data/docs/rails.md +70 -0
- data/lib/aikido/zen/actor.rb +1 -1
- data/lib/aikido/zen/agent/heartbeats_manager.rb +66 -0
- data/lib/aikido/zen/agent.rb +100 -112
- data/lib/aikido/zen/collector/hosts.rb +15 -0
- data/lib/aikido/zen/collector/routes.rb +64 -0
- data/lib/aikido/zen/{stats → collector}/sink_stats.rb +1 -1
- data/lib/aikido/zen/collector/stats.rb +111 -0
- data/lib/aikido/zen/{stats → collector}/users.rb +6 -2
- data/lib/aikido/zen/collector.rb +117 -0
- data/lib/aikido/zen/config.rb +17 -11
- data/lib/aikido/zen/context.rb +8 -1
- data/lib/aikido/zen/errors.rb +3 -1
- data/lib/aikido/zen/event.rb +7 -4
- data/lib/aikido/zen/internals.rb +4 -0
- data/lib/aikido/zen/{libzen-v0.1.26.x86_64.dylib → libzen-v0.1.31.x86_64.dylib} +0 -0
- data/lib/aikido/zen/middleware/set_context.rb +4 -1
- data/lib/aikido/zen/rails_engine.rb +27 -18
- data/lib/aikido/zen/request/schema/builder.rb +0 -2
- data/lib/aikido/zen/request.rb +6 -0
- data/lib/aikido/zen/runtime_settings.rb +6 -11
- data/lib/aikido/zen/scanners/ssrf_scanner.rb +12 -6
- data/lib/aikido/zen/sinks/action_controller.rb +64 -0
- data/lib/aikido/zen/sinks/http.rb +1 -1
- data/lib/aikido/zen/sinks/pg.rb +13 -12
- data/lib/aikido/zen/sinks/typhoeus.rb +1 -1
- data/lib/aikido/zen/sinks.rb +1 -0
- data/lib/aikido/zen/version.rb +2 -2
- data/lib/aikido/zen/worker.rb +82 -0
- data/lib/aikido/zen.rb +55 -50
- data/tasklib/bench.rake +70 -0
- metadata +20 -9
- data/CODE_OF_CONDUCT.md +0 -132
- data/lib/aikido/zen/stats/routes.rb +0 -53
- data/lib/aikido/zen/stats.rb +0 -171
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0aa289d304c5e3c07a2f797988ef4dd3365d0798635a33872d1a8208a0b2945d
|
4
|
+
data.tar.gz: efd5caa2aafc56a5355198cd4e43f226c1aa44178078a2e7f47ae46b66b8dc8f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 360bc33ac62e7973369b9b1e72beb628d4efd08c5ccc64464360923493dc71d3f5069c73dc7c5dd62d33c4de242ce11c28496e67a44dd3109ef1bcd1396e0135
|
7
|
+
data.tar.gz: 00ddf6f7584bd29a3f556de726ac701a86bde8b5135a94d155c9a57a7c7d811f1d664a3905d41d2ee1c096329817f822dc67d83e06562a0360e15ae7f3f5acea
|
data/.simplecov
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Due to dependency resolution, on Ruby 2.x we're stuck with a _very_ old
|
4
|
+
# SimpleCov version, and it doesn't really give us any benefit to run coverage
|
5
|
+
# in separate ruby versions since we don't branch on ruby version in the code.
|
6
|
+
return if RUBY_VERSION < "3.0"
|
7
|
+
|
8
|
+
SimpleCov.start do
|
9
|
+
# Make sure SimpleCov waits until after the tests
|
10
|
+
# are finished to generate the coverage reports.
|
11
|
+
self.external_at_exit = true
|
12
|
+
|
13
|
+
enable_coverage :branch
|
14
|
+
minimum_coverage line: 95, branch: 85
|
15
|
+
|
16
|
+
add_filter "/test/"
|
17
|
+
end
|
18
|
+
|
19
|
+
# vim: ft=ruby
|
data/CHANGELOG.md
CHANGED
@@ -2,4 +2,20 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
+
## 0.1.1
|
6
|
+
|
7
|
+
### Fixed
|
8
|
+
|
9
|
+
- Avoid an error when sending the initial heartbeat if the Aikido server hasn't
|
10
|
+
received stats yet.
|
11
|
+
- Fix the SSRF scanner to ensure the port in the user-supplied payload matches
|
12
|
+
the port in the request.
|
13
|
+
- Don't break the HTTP.rb sink when a Zen context isn't set.
|
14
|
+
- Don't break the Typhoeus sink when a Zen context isn't set.
|
15
|
+
- Don't break the PG sink outside of Rails.
|
16
|
+
- Updated [libzen](https://github.com/AikidoSec/zen-internals) to v0.1.31 to
|
17
|
+
prevent flagging false positives in SQL queries with comments.
|
18
|
+
|
19
|
+
## 0.1.0
|
20
|
+
|
5
21
|
- Initial version
|
data/README.md
CHANGED
@@ -1,40 +1,153 @@
|
|
1
|
-
|
1
|
+
![Zen by Aikido for Ruby](./docs/banner.svg)
|
2
2
|
|
3
|
-
|
3
|
+
# Zen, in-app firewall for Ruby | by Aikido
|
4
|
+
|
5
|
+
Zen, your in-app firewall for peace of mind—at runtime.
|
6
|
+
|
7
|
+
Zen by Aikido is an embedded Web Application Firewall that autonomously protects
|
8
|
+
Ruby on Rails apps against common and critical attacks.
|
9
|
+
|
10
|
+
It protects your Rails apps by preventing user input containing dangerous
|
11
|
+
strings, preventing SQL injection and SSRF attacks. It runs embedded on your
|
12
|
+
Rails application, for simple installation and zero maintenance.
|
13
|
+
|
14
|
+
* 🛡️ [SQL injection attacks](https://www.aikido.dev/blog/the-state-of-sql-injections)
|
15
|
+
* 🛡️ [Server-side request forgery (SSRF)](https://github.com/AikidoSec/firewall-node/blob/main/docs/ssrf.md)
|
16
|
+
* 🛡️ [Command injection attacks](https://owasp.org/www-community/attacks/Command_Injection) (coming soon)
|
17
|
+
* 🛡️ [Path traversal attacks](https://owasp.org/www-community/attacks/Path_Traversal)
|
18
|
+
* 🛡️ [NoSQL injection attacks](https://www.aikido.dev/blog/web-application-security-vulnerabilities) (coming soon)
|
19
|
+
|
20
|
+
Zen operates autonomously on the same server as your Rails app to:
|
21
|
+
|
22
|
+
* ✅ Secure your app like a classic web application firewall (WAF), but with none of the infrastructure or cost.
|
23
|
+
* ✅ Rate limit specific API endpoints by IP or by user.
|
24
|
+
* ✅ Allow you to block specific users manually.
|
25
|
+
|
26
|
+
## Supported libraries and frameworks
|
27
|
+
|
28
|
+
Zen for Ruby 2.7+ is compatible with:
|
29
|
+
|
30
|
+
### Database drivers
|
31
|
+
|
32
|
+
* ✅ [sqlite3](https://github.com/sparklemotion/sqlite3-ruby) 1.x, 2.x
|
33
|
+
* ✅ [pg](https://github.com/ged/ruby-pg) 1.x
|
34
|
+
* ✅ [trilogy](https://github.com/trilogy-libraries/trilogy) 2.x
|
35
|
+
* ✅ [mysql2](https://github.com/brianmario/mysql2) 0.x
|
36
|
+
|
37
|
+
### ORMs and Query Builders
|
38
|
+
|
39
|
+
See list above for supported database drivers.
|
40
|
+
|
41
|
+
* ✅ [ActiveRecord](https://github.com/rails/rails)
|
42
|
+
* ✅ [Sequel](https://github.com/jeremyevans/sequel)
|
43
|
+
|
44
|
+
### HTTP Clients
|
45
|
+
|
46
|
+
* ✅ [net-http](https://github.com/ruby/net-http)
|
47
|
+
* ✅ [http.rb](https://github.com/httprb/http) 1.x, 2.x, 3.x, 4.x, 5.x
|
48
|
+
* ✅ [httpx](https://gitlab.com/os85/httpx) 1.x (1.1.3+)
|
49
|
+
* ✅ [HttpClient](https://github.com/nahi/httpclient) 2.x, 3.x
|
50
|
+
* ✅ [excon](https://github.com/excon/excon) 0.x (0.50.0+), 1.x
|
51
|
+
* ✅ [patron](https://github.com/toland/patron) 0.x (0.6.4+)
|
52
|
+
* ✅ [typhoeus](https://github.com/typhoeus/typhoeus) 0.x (0.5.0+), 1.x
|
53
|
+
* ✅ [curb](https://github.com/taf2/curb) 0.x (0.2.3+), 1.x
|
54
|
+
* ✅ [em-http-request](https://github.com/igrigorik/em-http-request) 1.x
|
55
|
+
* ✅ [async-http](https://github.com/igrigorik/em-http-request) 0.x (0.70.0+)
|
4
56
|
|
5
57
|
## Installation
|
6
58
|
|
7
|
-
|
59
|
+
We recommend testing Zen locally or on staging before deploying to production.
|
60
|
+
|
61
|
+
```
|
62
|
+
bundle add aikido-zen
|
63
|
+
```
|
64
|
+
|
65
|
+
or, if not using bundler:
|
66
|
+
|
67
|
+
```
|
68
|
+
gem install aikido-zen
|
69
|
+
```
|
8
70
|
|
9
|
-
|
71
|
+
For framework specific instructions, check out our docs:
|
10
72
|
|
11
|
-
|
73
|
+
* [Ruby on Rails apps](docs/rails.md)
|
12
74
|
|
13
|
-
|
75
|
+
## Running in production (blocking) mode
|
14
76
|
|
15
|
-
|
77
|
+
By default, Zen will only detect and report attacks to Aikido.
|
16
78
|
|
17
|
-
|
18
|
-
`rake test` to run the tests. You can also run `bin/console` for an interactive
|
19
|
-
prompt that will allow you to experiment.
|
79
|
+
To block requests, set the `AIKIDO_BLOCK` environment variable to `true`.
|
20
80
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
81
|
+
See [Reporting to Aikido](#reporting-to-your-aikido-security-dashboard) to learn
|
82
|
+
how to send events to Aikido.
|
83
|
+
|
84
|
+
## Reporting to your Aikido Security dashboard
|
85
|
+
|
86
|
+
> Aikido is your no nonsense application security platform. One central system
|
87
|
+
> that scans your source code & cloud, shows you what vulnerabilities matter,
|
88
|
+
> and how to fix them - fast. So you can get back to building.
|
89
|
+
|
90
|
+
Zen is a new product by Aikido. Built for developers to level up their security.
|
91
|
+
While Aikido scans, get Zen for always-on protection.
|
92
|
+
|
93
|
+
You can use some of Zen’s features without Aikido, of course. Peace of mind is
|
94
|
+
just a few lines of code away.
|
95
|
+
|
96
|
+
But you will get the most value by reporting your data to Aikido.
|
97
|
+
|
98
|
+
You will need an Aikido account and a token to report events to Aikido. If you
|
99
|
+
don't have an account, you can sign up for free.
|
100
|
+
|
101
|
+
Here's how:
|
102
|
+
|
103
|
+
* Log in to your Aikido account.
|
104
|
+
* Go to "Zen" on the sidebar.
|
105
|
+
* Click on "Add App".
|
106
|
+
* Choose a name for your App.
|
107
|
+
* Click "Continue to Install"
|
108
|
+
* Click "Generate Token".
|
109
|
+
* Copy the token.
|
110
|
+
* Set the token as an environment variable, `AIKIDO_TOKEN`, using
|
111
|
+
[dotenv](https://github.com/bkeepers/dotenv) or another method
|
112
|
+
of your choosing.
|
113
|
+
|
114
|
+
## Performance
|
115
|
+
|
116
|
+
We run a benchmark on every commit to ensure Zen has a minimal impact on your
|
117
|
+
application's performance.
|
118
|
+
|
119
|
+
For example, here's a benchmark that runs a single GET request to a Rails
|
120
|
+
endpoint that performs a single SQL SELECT query:
|
121
|
+
|
122
|
+
| Without Zen | With Zen | Difference |
|
123
|
+
|------------------|---------------|---------------|
|
124
|
+
| 3.527ms | 3.583ms | +0.056ms |
|
125
|
+
|
126
|
+
Using Ruby 3.3, Rails 7.1, SQLite 1.7, running on a MacBook Pro M1 Pro. Results
|
127
|
+
will vary based on hardware.
|
128
|
+
|
129
|
+
See [benchmarks](benchmarks) for more information.
|
130
|
+
|
131
|
+
## Bug bounty program
|
132
|
+
|
133
|
+
Our bug bounty program is public and can be found by all registered Intigriti
|
134
|
+
users at: https://app.intigriti.com/researcher/programs/aikido/aikidoruntime
|
26
135
|
|
27
136
|
## Contributing
|
28
137
|
|
29
|
-
|
30
|
-
intended to be a safe, welcoming space for collaboration, and contributors are
|
31
|
-
expected to adhere to the [code of conduct][coc].
|
138
|
+
See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for more information.
|
32
139
|
|
33
140
|
## Code of Conduct
|
34
141
|
|
35
|
-
|
36
|
-
|
37
|
-
|
142
|
+
See [CODE_OF_CONDUCT.md](.github/CODE_OF_CONDUCT.md) for more information.
|
143
|
+
|
144
|
+
## License
|
145
|
+
|
146
|
+
This program is offered under a commercial and under the AGPL license. You can
|
147
|
+
be released from the requirements of the AGPL license by purchasing a commercial
|
148
|
+
license. Buying such a license is mandatory as soon as you develop commercial
|
149
|
+
activities involving the Zen software without disclosing the source code of your
|
150
|
+
own applications.
|
38
151
|
|
39
|
-
|
40
|
-
|
152
|
+
For more information, please contact Aikido Security at this address:
|
153
|
+
support@aikido.dev or create an account at https://app.aikido.dev.
|
data/Rakefile
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
# Benchmarking Zen for Ruby
|
2
|
+
|
3
|
+
This directory contains the benchmarking scripts that we use to ensure adding
|
4
|
+
Zen to your application does not impact performance significantly.
|
5
|
+
|
6
|
+
We use [Grafana K6](https://k6.io) for these. For each sample application we
|
7
|
+
include in this repo under [sample_apps](../sample_apps), you should find
|
8
|
+
a script here that runs certain benchmarks against that app.
|
9
|
+
|
10
|
+
To run all the benchmarks, run the following from the root of the project:
|
11
|
+
|
12
|
+
```
|
13
|
+
$ bundle exec rake bench
|
14
|
+
```
|
15
|
+
|
16
|
+
In order to run a benchmarks against a single application, run the following
|
17
|
+
from the root of the project:
|
18
|
+
|
19
|
+
```
|
20
|
+
$ bundle exec rake bench:{app}:run
|
21
|
+
```
|
22
|
+
|
23
|
+
For example, for the `rails7.1_sql_injection` application:
|
24
|
+
|
25
|
+
```
|
26
|
+
$ bundle exec rake bench:rails7.1_sql_injection:run
|
27
|
+
```
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import http from 'k6/http';
|
2
|
+
import { textSummary } from 'https://jslib.k6.io/k6-summary/0.0.2/index.js';
|
3
|
+
import { check, sleep, fail } from 'k6';
|
4
|
+
import exec from 'k6/execution';
|
5
|
+
import { Trend } from 'k6/metrics';
|
6
|
+
|
7
|
+
const HTTP = {
|
8
|
+
withZen: {
|
9
|
+
get: (path, ...args) => http.get("http://localhost:3001" + path, ...args),
|
10
|
+
post: (path, ...args) => http.post("http://localhost:3001" + path, ...args)
|
11
|
+
},
|
12
|
+
withoutZen: {
|
13
|
+
get: (path, ...args) => http.get("http://localhost:3002" + path, ...args),
|
14
|
+
post: (path, ...args) => http.post("http://localhost:3002" + path, ...args)
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
18
|
+
function test(name, fn) {
|
19
|
+
const duration = tests[name].duration;
|
20
|
+
const overhead = tests[name].overhead;
|
21
|
+
|
22
|
+
const withZen = fn(HTTP.withZen);
|
23
|
+
const withoutZen = fn(HTTP.withoutZen);
|
24
|
+
|
25
|
+
const timeWithZen = withZen.timings.duration,
|
26
|
+
timeWithoutZen = withoutZen.timings.duration;
|
27
|
+
|
28
|
+
duration.add(timeWithZen - timeWithoutZen);
|
29
|
+
|
30
|
+
const ratio = withZen.timings.duration / withoutZen.timings.duration;
|
31
|
+
overhead.add(100 * (timeWithZen - timeWithoutZen) / timeWithoutZen)
|
32
|
+
}
|
33
|
+
|
34
|
+
const defaultHeaders = {
|
35
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36",
|
36
|
+
};
|
37
|
+
|
38
|
+
const tests = {
|
39
|
+
test_post_page_with_json_body: {
|
40
|
+
duration: new Trend("test_post_page_with_json_body"),
|
41
|
+
overhead: new Trend("test_overhead_with_json_body")
|
42
|
+
},
|
43
|
+
test_get_page_without_attack: {
|
44
|
+
duration: new Trend("test_get_page_without_attack"),
|
45
|
+
overhead: new Trend("test_overhead_without_attack")
|
46
|
+
},
|
47
|
+
test_get_page_with_sql_injection: {
|
48
|
+
duration: new Trend("test_get_page_with_sql_injection"),
|
49
|
+
overhead: new Trend("test_overhead_with_sql_injection"),
|
50
|
+
}
|
51
|
+
}
|
52
|
+
export const options = {
|
53
|
+
vus: 1, // Number of virtual users
|
54
|
+
iterations: 200,
|
55
|
+
thresholds: {
|
56
|
+
test_post_page_with_json_body: ["med<10"],
|
57
|
+
test_get_page_without_attack: ["med<10"],
|
58
|
+
test_get_page_with_sql_injection: ["med<10"],
|
59
|
+
}
|
60
|
+
};
|
61
|
+
|
62
|
+
const expectAttack = http.expectedStatuses(500);
|
63
|
+
|
64
|
+
export default function () {
|
65
|
+
test("test_post_page_with_json_body",
|
66
|
+
(http) => http.post("/cats", JSON.stringify({cat: {name: "Féline Dion"}}), {
|
67
|
+
headers: {"Content-Type": "application/json"}
|
68
|
+
})
|
69
|
+
)
|
70
|
+
test("test_get_page_without_attack", (http) => http.get("/cats"))
|
71
|
+
test("test_get_page_with_sql_injection", (http) =>
|
72
|
+
http.get("/cats/1'%20OR%20''='", {responseCallback: expectAttack})
|
73
|
+
)
|
74
|
+
}
|