aikido-zen 0.1.1-x86_64-mingw-64 → 1.0.0.pre.beta.1-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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +7 -0
  3. data/CHANGELOG.md +4 -0
  4. data/README.md +11 -2
  5. data/benchmarks/README.md +8 -12
  6. data/benchmarks/rails7.1_sql_injection.js +30 -34
  7. data/docs/banner.svg +128 -129
  8. data/docs/config.md +8 -6
  9. data/docs/rails.md +1 -1
  10. data/lib/aikido/zen/agent.rb +13 -9
  11. data/lib/aikido/zen/api_client.rb +17 -7
  12. data/lib/aikido/zen/attack.rb +105 -36
  13. data/lib/aikido/zen/background_worker.rb +52 -0
  14. data/lib/aikido/zen/collector/routes.rb +2 -0
  15. data/lib/aikido/zen/collector.rb +31 -4
  16. data/lib/aikido/zen/config.rb +55 -20
  17. data/lib/aikido/zen/detached_agent/agent.rb +78 -0
  18. data/lib/aikido/zen/detached_agent/front_object.rb +37 -0
  19. data/lib/aikido/zen/detached_agent/server.rb +41 -0
  20. data/lib/aikido/zen/detached_agent.rb +2 -0
  21. data/lib/aikido/zen/errors.rb +18 -1
  22. data/lib/aikido/zen/event.rb +4 -2
  23. data/lib/aikido/zen/libzen-v0.1.37.x86_64.dll +0 -0
  24. data/lib/aikido/zen/middleware/check_allowed_addresses.rb +2 -14
  25. data/lib/aikido/zen/middleware/middleware.rb +11 -0
  26. data/lib/aikido/zen/middleware/{throttler.rb → rack_throttler.rb} +11 -13
  27. data/lib/aikido/zen/middleware/request_tracker.rb +190 -0
  28. data/lib/aikido/zen/middleware/set_context.rb +1 -4
  29. data/lib/aikido/zen/outbound_connection_monitor.rb +4 -0
  30. data/lib/aikido/zen/payload.rb +2 -0
  31. data/lib/aikido/zen/rails_engine.rb +12 -0
  32. data/lib/aikido/zen/rate_limiter/breaker.rb +3 -3
  33. data/lib/aikido/zen/rate_limiter.rb +7 -12
  34. data/lib/aikido/zen/request/rails_router.rb +6 -18
  35. data/lib/aikido/zen/request/schema/auth_schemas.rb +14 -0
  36. data/lib/aikido/zen/request/schema/builder.rb +0 -2
  37. data/lib/aikido/zen/request/schema/definition.rb +0 -5
  38. data/lib/aikido/zen/request/schema.rb +18 -3
  39. data/lib/aikido/zen/runtime_settings.rb +2 -2
  40. data/lib/aikido/zen/scanners/path_traversal/helpers.rb +65 -0
  41. data/lib/aikido/zen/scanners/path_traversal_scanner.rb +63 -0
  42. data/lib/aikido/zen/scanners/shell_injection/helpers.rb +159 -0
  43. data/lib/aikido/zen/scanners/shell_injection_scanner.rb +64 -0
  44. data/lib/aikido/zen/scanners/sql_injection_scanner.rb +4 -6
  45. data/lib/aikido/zen/scanners/ssrf/private_ip_checker.rb +33 -21
  46. data/lib/aikido/zen/scanners/ssrf_scanner.rb +15 -7
  47. data/lib/aikido/zen/scanners/stored_ssrf_scanner.rb +6 -0
  48. data/lib/aikido/zen/scanners.rb +2 -0
  49. data/lib/aikido/zen/sink.rb +6 -1
  50. data/lib/aikido/zen/sinks/action_controller.rb +34 -15
  51. data/lib/aikido/zen/sinks/file.rb +120 -0
  52. data/lib/aikido/zen/sinks/kernel.rb +73 -0
  53. data/lib/aikido/zen/sinks/socket.rb +13 -0
  54. data/lib/aikido/zen/sinks.rb +8 -0
  55. data/lib/aikido/zen/system_info.rb +1 -1
  56. data/lib/aikido/zen/version.rb +2 -2
  57. data/lib/aikido/zen/worker.rb +5 -0
  58. data/lib/aikido/zen.rb +54 -8
  59. data/tasklib/bench.rake +31 -7
  60. data/tasklib/wrk.rb +88 -0
  61. metadata +22 -8
  62. data/lib/aikido/zen/libzen-v0.1.31.x86_64.dll +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2bf73cb057d4bce27e28d941fd1230ff3f27d0e8f4ce284c2fcc3adc86848ee7
4
- data.tar.gz: 55fb8ec7251826f85749a4ab35ddc50963d3cabde8fcacd3b2fa5ff0090e697f
3
+ metadata.gz: 612c8be80af943e42d497eef7621c500acce361d8a269f35042df322b97f44ca
4
+ data.tar.gz: 50ead136c69a3c8a90896bf430b7632b3771ea0a2c2891cdb57abda83fb3220f
5
5
  SHA512:
6
- metadata.gz: 977f2a178da981f428c70ef18a43e6874eda2b328d6d665a063b5c0dd770839e9814c447724737e86e3ac0419ccd5ceda7ce666dec869aac9e5ba4d4a820fd5c
7
- data.tar.gz: c54e7c8ac63affb10bfae8b13515c817024d0a9ccfeedca4e1395fe81db378c6d055f941018dfc35323643cbc3e34e05f3ae309c05739536699203ca5ccd5a0d
6
+ metadata.gz: 97315d03785d9dc8b4dda1d31ff7ccb299812d5da789b2a5473883c975b07fac9c0c1d5336030f27bb9e21f162c2726d51dd39ffb00071e9d550f111aa098092
7
+ data.tar.gz: a83eb6028d858b19dbb3514d9a7565b804fcfa9d812d8670dce2a0abf41c750b7b9328208b44f60192018652d0dc5c8dec144d2caea6d920ec45362e1fb09ea4
data/.simplecov CHANGED
@@ -4,6 +4,7 @@
4
4
  # SimpleCov version, and it doesn't really give us any benefit to run coverage
5
5
  # in separate ruby versions since we don't branch on ruby version in the code.
6
6
  return if RUBY_VERSION < "3.0"
7
+ return if ENV["DISABLE_COVERAGE"] == "true"
7
8
 
8
9
  SimpleCov.start do
9
10
  # Make sure SimpleCov waits until after the tests
@@ -14,6 +15,12 @@ SimpleCov.start do
14
15
  minimum_coverage line: 95, branch: 85
15
16
 
16
17
  add_filter "/test/"
18
+
19
+ # WebMock excludes EM-HTTP-Request on Ruby 3.4:
20
+ # https://github.com/c960657/webmock/commit/34d16285dbcc574c90b273a89f16cb5fb9f4222a
21
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0") && Gem.loaded_specs["em-http-request"].version <= Gem::Version.new("1.1.7")
22
+ add_filter "lib/aikido/zen/sinks/em_http.rb"
23
+ end
17
24
  end
18
25
 
19
26
  # vim: ft=ruby
data/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ### Fixed
6
+
7
+ - Avoid an infinite loop when checking for SSRFs in a circular redirects loop.
8
+
5
9
  ## 0.1.1
6
10
 
7
11
  ### Fixed
data/README.md CHANGED
@@ -1,5 +1,10 @@
1
1
  ![Zen by Aikido for Ruby](./docs/banner.svg)
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/aikido-zen.svg?icon=si%3Arubygems&style=flat)](https://badge.fury.io/rb/aikido-zen)
4
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)
5
+ [![Unit tests](https://github.com/AikidoSec/firewall-ruby/actions/workflows/main.yml/badge.svg)](https://github.com/AikidoSec/firewall-ruby/actions/workflows/main.yml)
6
+ [![Release](https://github.com/AikidoSec/firewall-ruby/actions/workflows/release.yml/badge.svg)](https://github.com/AikidoSec/firewall-ruby/actions/workflows/release.yml)
7
+
3
8
  # Zen, in-app firewall for Ruby | by Aikido
4
9
 
5
10
  Zen, your in-app firewall for peace of mind—at runtime.
@@ -13,8 +18,8 @@ Rails application, for simple installation and zero maintenance.
13
18
 
14
19
  * 🛡️ [SQL injection attacks](https://www.aikido.dev/blog/the-state-of-sql-injections)
15
20
  * 🛡️ [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)
21
+ * 🛡️ [Command injection attacks](https://www.aikido.dev/blog/command-injection-in-2024-unpacked) (coming soon)
22
+ * 🛡️ [Path traversal attacks](https://www.aikido.dev/blog/path-traversal-in-2024-the-year-unpacked) (coming soon)
18
23
  * 🛡️ [NoSQL injection attacks](https://www.aikido.dev/blog/web-application-security-vulnerabilities) (coming soon)
19
24
 
20
25
  Zen operates autonomously on the same server as your Rails app to:
@@ -81,6 +86,10 @@ To block requests, set the `AIKIDO_BLOCK` environment variable to `true`.
81
86
  See [Reporting to Aikido](#reporting-to-your-aikido-security-dashboard) to learn
82
87
  how to send events to Aikido.
83
88
 
89
+ ## Additional configuration
90
+
91
+ [Configure Zen using environment variables for authentication, mode settings, debugging, and more.](https://help.aikido.dev/doc/configuration-via-env-vars/docrSItUkeR9)
92
+
84
93
  ## Reporting to your Aikido Security dashboard
85
94
 
86
95
  > Aikido is your no nonsense application security platform. One central system
data/benchmarks/README.md CHANGED
@@ -1,27 +1,23 @@
1
1
  # Benchmarking Zen for Ruby
2
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
3
 
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.
4
+ We use [WRK](https://github.com/wg/wrk) & [Grafana K6](https://k6.io) for these.
9
5
 
10
- To run all the benchmarks, run the following from the root of the project:
6
+ WRK benchmarks are only requesting a URL (`/benchmark`). In case you want to add more
7
+ of those test, you have to code them in the file `tasklib/bench.rake`.
11
8
 
12
- ```
13
- $ bundle exec rake bench
14
- ```
9
+ K6 tests are defined in `benchmarks` folder. They are a javascript file, with calls
10
+ to different endpoints.
15
11
 
16
12
  In order to run a benchmarks against a single application, run the following
17
13
  from the root of the project:
18
14
 
19
15
  ```
20
- $ bundle exec rake bench:{app}:run
16
+ $ BUNDLE_GEMFILE=./sample_apps/{app}/Gemfile bundle exec rake bench:{app}:(k6|wrk)_run
21
17
  ```
22
18
 
23
- For example, for the `rails7.1_sql_injection` application:
19
+ For example, for the WRK of `rails7.1_benchmark` application:
24
20
 
25
21
  ```
26
- $ bundle exec rake bench:rails7.1_sql_injection:run
22
+ $ BUNDLE_GEMFILE=./sample_apps/rails7.1_benchmark/Gemfile bundle exec rake bench:rails7.1_benchmark:wrk_run
27
23
  ```
@@ -1,8 +1,5 @@
1
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';
2
+ import {Trend} from 'k6/metrics';
6
3
 
7
4
  const HTTP = {
8
5
  withZen: {
@@ -16,59 +13,58 @@ const HTTP = {
16
13
  }
17
14
 
18
15
  function test(name, fn) {
19
- const duration = tests[name].duration;
20
- const overhead = tests[name].overhead;
21
-
22
16
  const withZen = fn(HTTP.withZen);
23
17
  const withoutZen = fn(HTTP.withoutZen);
18
+ const timeWithZen = withZen.timings.duration;
19
+ const timeWithoutZen = withoutZen.timings.duration;
24
20
 
25
- const timeWithZen = withZen.timings.duration,
26
- timeWithoutZen = withoutZen.timings.duration;
27
-
28
- duration.add(timeWithZen - timeWithoutZen);
21
+ tests[name].delta.add(timeWithZen - timeWithoutZen);
22
+ tests[name].overhead.add(100 * (timeWithZen - timeWithoutZen) / timeWithoutZen)
29
23
 
30
- const ratio = withZen.timings.duration / withoutZen.timings.duration;
31
- overhead.add(100 * (timeWithZen - timeWithoutZen) / timeWithoutZen)
24
+ tests[name].with_zen.add(timeWithZen);
25
+ tests[name].without_zen.add(timeWithoutZen);
32
26
  }
33
27
 
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
- };
28
+ function buildTestTrends(prefix) {
29
+ return {
30
+ delta: new Trend(`${prefix}_delta`),
31
+ with_zen: new Trend(`${prefix}_with_zen`),
32
+ without_zen: new Trend(`${prefix}_without_zen`),
33
+ overhead: new Trend(`${prefix}_overhead`)
34
+ };
35
+ }
37
36
 
38
37
  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
- }
38
+ test_post_page_with_json_body: buildTestTrends("test_post_page_with_json_body"),
39
+ test_get_page_without_attack: buildTestTrends("test_get_page_without_attack"),
40
+ test_get_page_with_sql_injection: buildTestTrends("test_get_page_with_sql_injection")
51
41
  }
52
42
  export const options = {
53
43
  vus: 1, // Number of virtual users
54
44
  iterations: 200,
55
45
  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"],
46
+ http_req_failed: ['rate==0'], // we are marking the attacks as expected, so we should have no errors
47
+ test_post_page_with_json_body_delta: ["med<10"],
48
+ test_get_page_without_attack_delta: ["med<10"],
49
+ test_get_page_with_sql_injection_delta: ["med<10"],
59
50
  }
60
51
  };
61
52
 
62
- const expectAttack = http.expectedStatuses(500);
53
+ const expectAttack = http.expectedStatuses(200, 500);
63
54
 
64
55
  export default function () {
65
56
  test("test_post_page_with_json_body",
66
57
  (http) => http.post("/cats", JSON.stringify({cat: {name: "Féline Dion"}}), {
67
- headers: {"Content-Type": "application/json"}
58
+ headers: {
59
+ "Content-Type": "application/json",
60
+ "Accept": "application/json"
61
+ }
68
62
  })
69
63
  )
64
+
70
65
  test("test_get_page_without_attack", (http) => http.get("/cats"))
66
+
71
67
  test("test_get_page_with_sql_injection", (http) =>
72
- http.get("/cats/1'%20OR%20''='", {responseCallback: expectAttack})
68
+ http.get("/cats/1'%20OR%20''='", { responseCallback: expectAttack })
73
69
  )
74
70
  }