Class: Aikido::Zen::AttackWave::Detector

Inherits:
Object
  • Object
show all
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

Instance Method Summary collapse

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

#samplesAikido::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.

Note:

Visible for testing.

This method returns an undefined value.

Flags the client IP as having triggered an attack wave for the cooldown period.

Parameters:

  • client_ip (String)


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.

Note:

Visible for testing.

Whether the client IP is within the cooldown period after triggering an attack wave.

Parameters:

  • client_ip (String)

Returns:

  • (Boolean)


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.

Parameters:

Returns:



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