Class: Aikido::Zen::AttackWave::Detector
- Inherits:
-
Object
- Object
- Aikido::Zen::AttackWave::Detector
- Defined in:
- lib/aikido/zen/attack_wave.rb
Overview
Tracks per-client-IP attack wave state.
In multiprocess deployments, the main process has a single instance that may be accessed concurrently from each forked worker process's Aikido::Zen::RPC::Server connection thread.
Instance Attribute Summary collapse
- #samples ⇒ Aikido::Zen::CappedSet readonly
Instance Method Summary collapse
-
#flag!(client_ip) ⇒ void
private
Flags the client IP as having triggered an attack wave for the cooldown period.
-
#flagged?(client_ip) ⇒ Boolean
private
Whether the client IP is within the cooldown period after triggering an attack wave.
-
#initialize(config: Aikido::Zen.config, clock: nil) ⇒ Detector
constructor
A new instance of Detector.
-
#record(client_ip, sample) ⇒ Array<Aikido::Zen::AttackWave::Sample>?
Records a suspicious sample and, if it crosses the threshold for triggering an attack wave, flags the client IP as having just triggered an attack wave.
Constructor Details
#initialize(config: Aikido::Zen.config, clock: nil) ⇒ Detector
Returns a new instance of Detector.
17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/aikido/zen/attack_wave.rb', line 17 def initialize(config: Aikido::Zen.config, clock: nil) @config = config @mutex = Mutex.new @event_times = Cache.new(@config.attack_wave_max_cache_entries, ttl: @config.attack_wave_min_time_between_events, clock: clock) @request_counts = Cache.new(@config.attack_wave_max_cache_entries, 0, ttl: @config.attack_wave_min_time_between_requests, clock: clock) @samples = Cache.new(@config.attack_wave_max_cache_entries, ttl: @config.attack_wave_min_time_between_requests, clock: clock) do CappedSet.new(@config.attack_wave_max_cache_samples) end end |
Instance Attribute Details
#samples ⇒ Aikido::Zen::CappedSet (readonly)
15 16 17 |
# File 'lib/aikido/zen/attack_wave.rb', line 15 def samples @samples end |
Instance Method Details
#flag!(client_ip) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Visible for testing.
This method returns an undefined value.
Flags the client IP as having triggered an attack wave for the cooldown period.
51 52 53 |
# File 'lib/aikido/zen/attack_wave.rb', line 51 def flag!(client_ip) @event_times[client_ip] = Time.now.utc end |
#flagged?(client_ip) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Visible for testing.
Whether the client IP is within the cooldown period after triggering an attack wave.
39 40 41 |
# File 'lib/aikido/zen/attack_wave.rb', line 39 def flagged?(client_ip) !!@event_times[client_ip] end |
#record(client_ip, sample) ⇒ Array<Aikido::Zen::AttackWave::Sample>?
Records a suspicious sample and, if it crosses the threshold for triggering an attack wave, flags the client IP as having just triggered an attack wave.
This method is synchronized to prevent concurrent calls for the same client IP from crossing the threshold in the same instant.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/aikido/zen/attack_wave.rb', line 65 def record(client_ip, sample) @mutex.synchronize do return nil if flagged?(client_ip) request_count = @request_counts[client_ip] += 1 @samples[client_ip] <<= sample return nil if request_count < @config.attack_wave_threshold flag!(client_ip) @samples[client_ip].to_a end end |