sqreen 1.15.0-java → 1.15.5-java

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sqreen/actions.rb +114 -43
  3. data/lib/sqreen/callback_tree.rb +16 -3
  4. data/lib/sqreen/callbacks.rb +7 -34
  5. data/lib/sqreen/capped_queue.rb +5 -1
  6. data/lib/sqreen/configuration.rb +4 -0
  7. data/lib/sqreen/deliveries/batch.rb +7 -4
  8. data/lib/sqreen/event.rb +4 -0
  9. data/lib/sqreen/events/request_record.rb +40 -7
  10. data/lib/sqreen/frameworks/generic.rb +0 -2
  11. data/lib/sqreen/frameworks/request_recorder.rb +14 -1
  12. data/lib/sqreen/instrumentation.rb +57 -33
  13. data/lib/sqreen/js/mini_racer_adapter.rb +46 -8
  14. data/lib/sqreen/metrics/average.rb +1 -1
  15. data/lib/sqreen/metrics/base.rb +4 -2
  16. data/lib/sqreen/metrics/binning.rb +3 -2
  17. data/lib/sqreen/metrics/collect.rb +1 -1
  18. data/lib/sqreen/metrics/sum.rb +1 -1
  19. data/lib/sqreen/metrics_store.rb +10 -5
  20. data/lib/sqreen/mono_time.rb +18 -0
  21. data/lib/sqreen/performance_notifications.rb +13 -38
  22. data/lib/sqreen/performance_notifications/binned_metrics.rb +12 -14
  23. data/lib/sqreen/performance_notifications/log.rb +6 -1
  24. data/lib/sqreen/performance_notifications/log_performance.rb +3 -1
  25. data/lib/sqreen/performance_notifications/metrics.rb +6 -3
  26. data/lib/sqreen/performance_notifications/newrelic.rb +6 -2
  27. data/lib/sqreen/remote_command.rb +26 -0
  28. data/lib/sqreen/rule_attributes.rb +1 -0
  29. data/lib/sqreen/rule_callback.rb +38 -0
  30. data/lib/sqreen/rules_callbacks/binding_accessor_matcher.rb +3 -2
  31. data/lib/sqreen/rules_callbacks/blacklist_ips.rb +1 -1
  32. data/lib/sqreen/rules_callbacks/run_block_user_actions.rb +1 -1
  33. data/lib/sqreen/rules_callbacks/run_req_start_actions.rb +8 -2
  34. data/lib/sqreen/runner.rb +11 -8
  35. data/lib/sqreen/sdk.rb +7 -1
  36. data/lib/sqreen/session.rb +4 -0
  37. data/lib/sqreen/trie.rb +274 -0
  38. data/lib/sqreen/version.rb +1 -1
  39. metadata +4 -2
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'sqreen/exception'
5
5
  require 'sqreen/metrics'
6
+ require 'sqreen/mono_time'
6
7
 
7
8
  module Sqreen
8
9
  # This store and register metrics
@@ -17,6 +18,7 @@ module Sqreen
17
18
  class AlreadyRegisteredMetric < Sqreen::Exception
18
19
  end
19
20
 
21
+ # definition keys
20
22
  NAME_KEY = 'name'.freeze
21
23
  KIND_KEY = 'kind'.freeze
22
24
  PERIOD_KEY = 'period'.freeze
@@ -29,7 +31,7 @@ module Sqreen
29
31
 
30
32
  def initialize
31
33
  @store = []
32
- @metrics = {}
34
+ @metrics = {} # name => (metric, period, start)
33
35
  end
34
36
 
35
37
  # Definition contains a name,period and aggregate at least
@@ -54,17 +56,17 @@ module Sqreen
54
56
  @metrics.key?(name)
55
57
  end
56
58
 
59
+ # @params at [Time] when is the store emptied
57
60
  def update(name, at, key, value)
58
- at = at.utc
59
61
  metric, period, start = @metrics[name]
60
62
  raise UnregisteredMetric, "Unknown metric #{name}" unless metric
61
63
  next_sample(name, at) if start.nil? || (start + period) < at
62
- metric.update(at, key, value)
64
+ metric.update(key, value)
63
65
  end
64
66
 
65
67
  # Drains every metrics and returns the store content
66
68
  # @params at [Time] when is the store emptied
67
- def publish(flush = true, at = Time.now.utc)
69
+ def publish(flush = true, at = Sqreen.time)
68
70
  @metrics.each do |name, (_, period, start)|
69
71
  next_sample(name, at) if flush || !start.nil? && (start + period) < at
70
72
  end
@@ -78,10 +80,13 @@ module Sqreen
78
80
  def next_sample(name, at)
79
81
  metric = @metrics[name][0]
80
82
  r = metric.next_sample(at)
81
- @metrics[name][2] = at # start
83
+ @metrics[name][2] = at # new start
82
84
  if r
83
85
  r[NAME_KEY] = name
84
86
  obs = r[Metric::OBSERVATION_KEY]
87
+ start_of_mono = Time.now.utc - Sqreen.time
88
+ r[Metric::START_KEY] = start_of_mono + r[Metric::START_KEY]
89
+ r[Metric::FINISH_KEY] = start_of_mono + r[Metric::FINISH_KEY]
85
90
  @store << r if obs && (!obs.respond_to?(:empty?) || !obs.empty?)
86
91
  end
87
92
  r
@@ -0,0 +1,18 @@
1
+ module Sqreen
2
+ has_mono_time = begin
3
+ Process.clock_gettime Process::CLOCK_MONOTONIC
4
+ true
5
+ rescue StandardError
6
+ false
7
+ end
8
+
9
+ if has_mono_time
10
+ def self.time
11
+ Process.clock_gettime Process::CLOCK_MONOTONIC
12
+ end
13
+ else
14
+ def self.time
15
+ Time.now.to_f
16
+ end
17
+ end
18
+ end
@@ -1,12 +1,7 @@
1
1
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
 
4
- begin
5
- Process.clock_gettime Process::CLOCK_MONOTONIC
6
- SQREEN_MONO_TIME = Process::CLOCK_MONOTONIC
7
- rescue StandardError
8
- SQREEN_MONO_TIME = nil
9
- end
4
+ require 'sqreen/mono_time'
10
5
 
11
6
  module Sqreen
12
7
  # This module enable us to keep track of sqreen resource usage
@@ -17,39 +12,29 @@ module Sqreen
17
12
  @subscriptions_all = {}
18
13
  @subscription_id = 0
19
14
  class << self
20
- # Subsribe to receive notificiations about an event
21
- # returns a subscription indentitifcation
15
+ # Subscribe to receive notifications about an event
16
+ # returns a subscription identification
22
17
  def subscribe(&block)
23
18
  id = (@subscription_id += 1)
24
19
  @subscriptions_all[id] = block
25
20
  id
26
21
  end
27
22
 
28
- if SQREEN_MONO_TIME
29
- def time
30
- Process.clock_gettime(SQREEN_MONO_TIME)
31
- end
32
- else
33
- def time
34
- Time.now
35
- end
36
- end
37
-
38
23
  # Is there a subscriber
39
24
  def listen_for?
40
25
  !@subscriptions_all.empty?
41
26
  end
42
27
 
43
28
  # Instrument a call identified by key
44
- def instrument(key, meta = {}, &block)
29
+ def instrument(rule, cb, meta = {}, &block)
45
30
  return yield unless listen_for?
46
- _instrument(key, meta, &block)
31
+ _instrument(rule, cb, meta, &block)
47
32
  end
48
33
 
49
- def notify(key, start, stop, meta = {})
34
+ def notify(rule, cb, start, stop, meta = {})
50
35
  return unless listen_for?
51
36
  notifiers.each do |callable|
52
- callable.call(key, start, stop, meta)
37
+ callable.call(rule, cb, start, stop, meta)
53
38
  end
54
39
  end
55
40
 
@@ -70,22 +55,12 @@ module Sqreen
70
55
  @subscriptions_all.values
71
56
  end
72
57
 
73
- if SQREEN_MONO_TIME
74
- def _instrument(key, meta)
75
- start = Process.clock_gettime(SQREEN_MONO_TIME)
76
- yield
77
- ensure
78
- stop = Process.clock_gettime(SQREEN_MONO_TIME)
79
- notify(key, start, stop, meta)
80
- end
81
- else
82
- def _instrument(key, meta)
83
- start = Time.now
84
- yield
85
- ensure
86
- stop = Time.now
87
- notify(key, start, stop, meta)
88
- end
58
+ def _instrument(rule, cb, meta)
59
+ start = Sqreen.time
60
+ yield
61
+ ensure
62
+ stop = Sqreen.time
63
+ notify(rule, cb, start, stop, meta)
89
64
  end
90
65
  end
91
66
  end
@@ -16,8 +16,6 @@ module Sqreen
16
16
  EVENT_TOTAL_TIME = 'sq'.freeze # sqreen total overhead callback time
17
17
  EVENT_PERCENT = 'pct'.freeze # sqreen total overhead percent of time
18
18
 
19
- EVT_NAME_REGEXP = %r{\ACallbacks/([^/]+)/([^/]+)\z}
20
-
21
19
  # @param metrics_store [Sqreen::MetricsStore]
22
20
  def initialize(metrics_store, period, perf_metric_opts, perf_metric_percent_opts)
23
21
  @metrics_store = metrics_store
@@ -49,32 +47,28 @@ module Sqreen
49
47
  @subid = nil
50
48
  end
51
49
 
52
- def log(event, start, finish, _meta)
53
- return unless event =~ EVT_NAME_REGEXP
54
- rule, cb = Regexp.last_match.captures
55
-
50
+ def log(rule, cb, start, finish, _meta)
56
51
  metric_name = "sq.#{rule}.#{cb}"
57
52
  ensure_metric(metric_name)
58
53
 
59
- finish_time = SQREEN_MONO_TIME ? Time.now.utc : finish
60
54
  time_millis = (finish - start) * 1000
61
55
  # Ensure we always have a timings if we somehow missed the request start
62
- SharedStorage[:sqreen_request_time] ||= 0
63
- SharedStorage[:sqreen_request_time] += time_millis
64
- metrics_store.update(metric_name, finish_time, nil, time_millis)
56
+ SharedStorage[:sqreen_request_time] =
57
+ (SharedStorage[:sqreen_request_time] || 0) + time_millis
58
+ metrics_store.update(metric_name, finish, nil, time_millis)
65
59
  end
66
60
 
67
61
  def start_request
68
- SharedStorage[:request_start_time] = PerformanceNotifications.time
62
+ SharedStorage[:request_start_time] = Sqreen.time
69
63
  SharedStorage[:sqreen_request_time] = 0.0
70
64
  end
71
65
 
72
66
  def finish_request
73
67
  start_time = SharedStorage[:request_start_time]
74
- finish_time = PerformanceNotifications.time
68
+ finish_time = Sqreen.time
75
69
  duration_millis = (finish_time - start_time) * 1000
76
70
 
77
- finish_time_obj = SQREEN_MONO_TIME ? Time.now.utc : finish_time
71
+ finish_time_obj = Time.now.utc
78
72
  # format of evt is [cat, key, value, timestamp]
79
73
  Sqreen.observations_queue.push(
80
74
  [EVENT_REQ, nil, duration_millis, finish_time_obj]
@@ -108,7 +102,11 @@ module Sqreen
108
102
  class << self
109
103
  # @return [Sqreen::PerformanceNotifications::BinnedMetrics]
110
104
  attr_reader :instance
111
- def enable(metrics_store, period = 60, base = DEFAULT_PERF_BASE, factor = DEFAULT_PERF_UNIT, base_pct = DEFAULT_PERF_PCT_BASE, factor_pct = DEFAULT_PERF_PCT_UNIT)
105
+ def enable(metrics_store, period = 60,
106
+ base = DEFAULT_PERF_BASE,
107
+ factor = DEFAULT_PERF_UNIT,
108
+ base_pct = DEFAULT_PERF_PCT_BASE,
109
+ factor_pct = DEFAULT_PERF_PCT_UNIT)
112
110
  disable
113
111
  @instance = new(metrics_store, period,
114
112
  {'base'=> base, 'factor' => factor},
@@ -10,14 +10,19 @@ module Sqreen
10
10
  @subid = nil
11
11
  @facility = nil
12
12
  class << self
13
- def log(event, start, finish, meta)
13
+ def log(rule, cb, start, finish, meta)
14
14
  (@facility || Sqreen.log).debug do
15
15
  meta_str = nil
16
16
  meta_str = ": #{meta.inspect}" unless meta.empty?
17
+ event = event_name(rule, cb)
17
18
  format('%s took %.2fms%s', event, (finish - start) * 1000, meta_str)
18
19
  end
19
20
  end
20
21
 
22
+ def event_name(rule, cb)
23
+ "Callbacks/#{rule}/#{cb}"
24
+ end
25
+
21
26
  def enable(facility = nil)
22
27
  return unless @subid.nil?
23
28
  @facility = facility
@@ -2,6 +2,7 @@
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
 
4
4
  require 'sqreen/performance_notifications'
5
+ require 'sqreen/performance_notifications/log'
5
6
 
6
7
  module Sqreen
7
8
  module PerformanceNotifications
@@ -23,7 +24,8 @@ module Sqreen
23
24
  SharedStorage.set(:log_performance_timings, value)
24
25
  end
25
26
 
26
- def log(event, start, finish, _meta)
27
+ def log(rule, cb, start, finish, _meta)
28
+ event = event_name(rule, cb)
27
29
  timings << [event, start, finish]
28
30
  end
29
31
 
@@ -2,17 +2,20 @@
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
 
4
4
  require 'sqreen/performance_notifications'
5
+ require 'sqreen/performance_notifications/log'
6
+ require 'sqreen/runner'
5
7
 
6
8
  module Sqreen
7
9
  module PerformanceNotifications
8
10
  # Log performances in sqreen metrics_store
9
- class Metrics
11
+ class Metrics < Log
10
12
  @subid = nil
11
13
  @facility = nil
12
14
  class << self
13
15
  EVENT_CAT = 'sqreen_time'.freeze
14
- def log(event, start, finish, _meta)
15
- evt = [EVENT_CAT, event, (finish - start) * 1000, SQREEN_MONO_TIME ? Time.now.utc : finish]
16
+ def log(rule, cb, start, finish, _meta)
17
+ event = event_name(rule, cb)
18
+ evt = [EVENT_CAT, event, (finish - start) * 1000, Time.now.utc]
16
19
  Sqreen.observations_queue.push(evt)
17
20
  end
18
21
 
@@ -2,11 +2,14 @@
2
2
  # Please refer to our terms for more information: https://www.sqreen.io/terms.html
3
3
 
4
4
  require 'sqreen/performance_notifications'
5
+ require 'sqreen/performance_notifications/log'
6
+ require 'sqreen/log'
7
+ require 'sqreen/shared_storage'
5
8
 
6
9
  module Sqreen
7
10
  module PerformanceNotifications
8
11
  # Log performances on the console
9
- class NewRelic
12
+ class NewRelic < Log
10
13
  @subid = nil
11
14
  @level = 0
12
15
 
@@ -24,7 +27,8 @@ module Sqreen
24
27
  SharedStorage.set(:log_performance_nr_timings, value)
25
28
  end
26
29
 
27
- def log(event, start, finish, _meta)
30
+ def log(rule, cb, start, finish, _meta)
31
+ event = event_name(rule, cb)
28
32
  timings << [event, start, finish]
29
33
  end
30
34
 
@@ -59,6 +59,7 @@ module Sqreen
59
59
  Sqreen.log.debug { commands.inspect }
60
60
  return res_list
61
61
  end
62
+ commands = coalesce_reloads(commands, res_list)
62
63
  commands.each do |cmd_json|
63
64
  Sqreen.log.debug { cmd_json }
64
65
  cmd = RemoteCommand.new(cmd_json)
@@ -69,6 +70,31 @@ module Sqreen
69
70
  res_list
70
71
  end
71
72
 
73
+ # will need changes if we ever distinguish forced/soft reloads
74
+ # ('force' parameter in the command)
75
+ def self.coalesce_reloads(commands, res_list)
76
+ new_commands = []
77
+ saw_rules_reload = false
78
+ commands.reverse_each do |cmd_json|
79
+ name = cmd_json['name']
80
+ unless name == 'rules_reload'
81
+ new_commands.unshift cmd_json
82
+ next
83
+ end
84
+
85
+ if saw_rules_reload
86
+ res_list[cmd_json['uuid']] =
87
+ { :status => false, :reason => "redundant rules_reload ignored" }
88
+ else
89
+ saw_rules_reload = true
90
+ new_commands.unshift cmd_json
91
+ next
92
+ end
93
+ end
94
+
95
+ new_commands
96
+ end
97
+
72
98
  def to_h
73
99
  {
74
100
  :name => @name,
@@ -19,6 +19,7 @@ module Sqreen
19
19
  METRICS = 'metrics'.freeze
20
20
  CONDITIONS = 'conditions'.freeze
21
21
  CALL_COUNT_INTERVAL = 'call_count_interval'.freeze
22
+ PRIORITY = 'priority'.freeze
22
23
 
23
24
  freeze
24
25
  end
@@ -47,6 +47,44 @@ module Sqreen
47
47
  @rule[Attrs::RULESPACK_ID]
48
48
  end
49
49
 
50
+ def priority
51
+ @rule[Attrs::PRIORITY] || super
52
+ end
53
+
54
+ # Record an attack event into Sqreen system
55
+ # @param infos [Hash] Additional information about request
56
+ def record_event(infos, at = Time.now.utc)
57
+ return unless framework
58
+ payload = {
59
+ :infos => infos,
60
+ :rulespack_id => rulespack_id,
61
+ :rule_name => rule_name,
62
+ :test => test,
63
+ :time => at,
64
+ }
65
+ if payload_tpl.include?('context')
66
+ payload[:backtrace] = Sqreen::Context.new.bt
67
+ end
68
+ framework.observe(:attacks, payload, payload_tpl)
69
+ end
70
+
71
+ # Record an exception that just occurred
72
+ # @param exception [Exception] Exception to send over
73
+ # @param infos [Hash] Additional contextual information
74
+ def record_exception(exception, infos = {}, at = Time.now.utc)
75
+ return unless framework
76
+ payload = {
77
+ :exception => exception,
78
+ :infos => infos,
79
+ :rulespack_id => rulespack_id,
80
+ :rule_name => rule_name,
81
+ :test => test,
82
+ :time => at,
83
+ :backtrace => exception.backtrace || Sqreen::Context.bt,
84
+ }
85
+ framework.observe(:sqreen_exceptions, payload)
86
+ end
87
+
50
88
  # Recommend taking an action (optionnally adding more data/context)
51
89
  #
52
90
  # This will format the requested action and optionnally
@@ -3,6 +3,7 @@
3
3
 
4
4
  require 'sqreen/rule_callback'
5
5
  require 'sqreen/binding_accessor'
6
+ require 'sqreen/mono_time'
6
7
  require 'sqreen/rules_callbacks/matcher_rule'
7
8
 
8
9
  module Sqreen
@@ -49,7 +50,7 @@ module Sqreen
49
50
 
50
51
  def pre(inst, args, budget = nil, &_block)
51
52
  unless budget.nil?
52
- finish = budget + Sqreen::PerformanceNotifications.time.to_f
53
+ finish = budget + Sqreen.time
53
54
  end
54
55
  resol_cache = Hash.new do |hash, accessor|
55
56
  hash[accessor] = accessor.resolve(binding, framework, inst, args)
@@ -61,7 +62,7 @@ module Sqreen
61
62
  next unless val.respond_to?(:each)
62
63
  next if val.respond_to?(:seek)
63
64
  val.each do |v|
64
- if !budget.nil? && Sqreen::PerformanceNotifications.time.to_f > finish
65
+ if !budget.nil? && Sqreen.time > finish
65
66
  return nil
66
67
  end
67
68
  next if !v.is_a?(String) || (!matcher.min_size.nil? && v.size < matcher.min_size)
@@ -23,7 +23,7 @@ module Sqreen
23
23
  return unless found
24
24
  Sqreen.log.debug { "Found blacklisted IP #{ip} - found: #{found}" }
25
25
  record_observation('blacklisted', found, 1)
26
- advise_action(:raise)
26
+ advise_action(:raise, :skip_rem_cbs => true)
27
27
  end
28
28
 
29
29
  protected