sqreen 1.19.3-java → 1.20.0-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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/lib/sqreen/aggregated_metric.rb +25 -0
  4. data/lib/sqreen/configuration.rb +7 -3
  5. data/lib/sqreen/deliveries/batch.rb +4 -1
  6. data/lib/sqreen/deliveries/simple.rb +4 -0
  7. data/lib/sqreen/event.rb +7 -5
  8. data/lib/sqreen/events/attack.rb +23 -18
  9. data/lib/sqreen/events/remote_exception.rb +0 -22
  10. data/lib/sqreen/events/request_record.rb +15 -70
  11. data/lib/sqreen/frameworks/request_recorder.rb +13 -2
  12. data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
  13. data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
  14. data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
  15. data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
  16. data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
  17. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
  18. data/lib/sqreen/legacy/old_event_submission_strategy.rb +221 -0
  19. data/lib/sqreen/legacy/waf_redactions.rb +49 -0
  20. data/lib/sqreen/metrics/base.rb +3 -0
  21. data/lib/sqreen/metrics_store.rb +22 -12
  22. data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
  23. data/lib/sqreen/rules.rb +4 -2
  24. data/lib/sqreen/rules/rule_cb.rb +2 -0
  25. data/lib/sqreen/rules/waf_cb.rb +11 -8
  26. data/lib/sqreen/runner.rb +43 -5
  27. data/lib/sqreen/sensitive_data_redactor.rb +19 -31
  28. data/lib/sqreen/session.rb +39 -37
  29. data/lib/sqreen/signals/conversions.rb +283 -0
  30. data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
  31. data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
  32. data/lib/sqreen/version.rb +1 -1
  33. metadata +42 -5
  34. data/lib/sqreen/backport.rb +0 -9
  35. data/lib/sqreen/backport/clock_gettime.rb +0 -74
  36. data/lib/sqreen/backport/original_name.rb +0 -88
@@ -0,0 +1,57 @@
1
+ # typed: ignore
2
+
3
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
+
6
+ require 'sqreen/kit/signals/point'
7
+ require 'sqreen/kit/signals/dto_helper'
8
+
9
+ # reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/attack/2020-01-01T00_00_00_000Z/schema.cue
10
+
11
+ module Sqreen
12
+ module Kit
13
+ module Signals
14
+ module Specialized
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ class Sqreen::Kit::Signals::Specialized::Attack < Sqreen::Kit::Signals::Point
21
+ add_mandatory_attrs :source, :time, :payload
22
+
23
+ validate_str_attr :signal_name, /\Asq\.agent\.attack\..+\z/
24
+ validate_str_attr :source, /\Asqreen:rule:[a-f0-9]{40}:.+\z/
25
+
26
+ def initialize(values = {})
27
+ self.payload_schema = Payload::SCHEMA_VERSION
28
+ self.time = values[:time] || Time.now
29
+ super
30
+ end
31
+
32
+ def payload=(payload)
33
+ unless payload.is_a?(Payload)
34
+ raise ArgumentError, "Payload should be a #{Payload}"
35
+ end
36
+ super
37
+ end
38
+
39
+ class Payload
40
+ include Sqreen::Kit::Signals::DtoHelper
41
+
42
+ SCHEMA_VERSION = 'attack/2020-01-01T00:00:00.000Z'.freeze
43
+
44
+ add_mandatory_attrs :test, :block, :infos
45
+
46
+ # all are mandatory
47
+
48
+ # @return [Boolean]
49
+ attr_accessor :test
50
+
51
+ # @return [Boolean]
52
+ attr_accessor :block
53
+
54
+ # @return [Hash{String|Symbol=>Object}]
55
+ attr_accessor :infos
56
+ end
57
+ end
@@ -0,0 +1,76 @@
1
+ # typed: ignore
2
+
3
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
+
6
+ require 'sqreen/kit/signals/metric'
7
+ require 'sqreen/kit/signals/dto_helper'
8
+
9
+ # reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/binning_metric/2020-01-01T00_00_00_000Z/schema.cue
10
+
11
+ module Sqreen
12
+ module Kit
13
+ module Signals
14
+ module Specialized
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ class Sqreen::Kit::Signals::Specialized::BinningMetric < Sqreen::Kit::Signals::Metric
21
+ add_mandatory_attrs :source, :time, :payload
22
+
23
+ validate_str_attr :signal_name, /\Asq\.agent\.metric\..+\z/
24
+
25
+ def initialize(args)
26
+ self.payload_schema = Payload::SCHEMA_VERSION
27
+ super
28
+ end
29
+
30
+ class Payload
31
+ include Sqreen::Kit::Signals::DtoHelper
32
+
33
+ SCHEMA_VERSION = 'metric_binning/2020-01-01T00:00:00.000Z'.freeze
34
+
35
+ add_mandatory_attrs :capture_interval_s,
36
+ :date_started,
37
+ :date_ended,
38
+ :max, :base, :unit, :bins
39
+
40
+ # mandatory
41
+ # @return [Integer]
42
+ attr_accessor :capture_interval_s
43
+
44
+ # mandatory
45
+ # @param [Time]
46
+ # @return [String]
47
+ attr_accessor_time :date_started
48
+
49
+ # mandatory
50
+ # @param [Time]
51
+ # @return [String]
52
+ attr_accessor_time :date_ended
53
+
54
+ # mandatory
55
+ # @return [Float]
56
+ attr_accessor :max
57
+
58
+ # mandatory
59
+ # @return [Float]
60
+ attr_accessor :base
61
+
62
+ # mandatory
63
+ # @return [Float]
64
+ attr_accessor :unit
65
+
66
+ # mandatory
67
+ # @return [Hash{Integer=>Integer}]
68
+ attr_accessor :bins
69
+
70
+ def to_h
71
+ {
72
+ kind: 'binning',
73
+ }.merge(super)
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,26 @@
1
+ # typed: ignore
2
+
3
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
+
6
+ require 'sqreen/kit/signals/trace'
7
+ require 'sqreen/kit/signals/context/http_context'
8
+ require 'sqreen/kit/signals/dto_helper'
9
+
10
+ module Sqreen
11
+ module Kit
12
+ module Signals
13
+ module Specialized
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ class Sqreen::Kit::Signals::Specialized::HttpTrace < Sqreen::Kit::Signals::Trace
20
+ add_mandatory_attrs :context
21
+
22
+ def initialize(values = {})
23
+ self.context_schema = ::Sqreen::Kit::Signals::Context::HttpContext::SCHEMA_VERSION
24
+ super
25
+ end
26
+ end
@@ -0,0 +1,50 @@
1
+ # typed: ignore
2
+
3
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
+
6
+ require 'sqreen/kit/signals/point'
7
+ require 'sqreen/kit/signals/dto_helper'
8
+
9
+ # reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/sdk_call/2020-01-01T00_00_00_000Z/schema.cue
10
+
11
+ module Sqreen
12
+ module Kit
13
+ module Signals
14
+ module Specialized
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ class Sqreen::Kit::Signals::Specialized::SdkTrackCall < Sqreen::Kit::Signals::Point
21
+ add_mandatory_attrs :source, :time, :payload
22
+
23
+ validate_str_attr :signal_name, /\Asq\.sdk\..+\z/
24
+
25
+ def initialize(values = {})
26
+ self.payload_schema = Payload::SCHEMA_VERSION
27
+ self.source = "sqreen:sdk:track"
28
+ self.time = values[:time] || Time.now
29
+ super
30
+ end
31
+
32
+ def payload=(payload)
33
+ unless payload.is_a?(Payload)
34
+ raise ArgumentError, "Payload should be a #{Payload}"
35
+ end
36
+ super
37
+ end
38
+
39
+ class Payload
40
+ include Sqreen::Kit::Signals::DtoHelper
41
+
42
+ SCHEMA_VERSION = 'track_event/2020-01-01T00:00:00.000Z'.freeze
43
+
44
+ # @return [Hash{String|Symbol=>Object}]
45
+ attr_accessor :properties
46
+
47
+ # @return [Hash{String|Symbol=>String}]
48
+ attr_accessor :user_identifiers
49
+ end
50
+ end
@@ -0,0 +1,57 @@
1
+ # typed: ignore
2
+
3
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
+
6
+ require 'sqreen/kit/signals/point'
7
+ require 'sqreen/kit/signals/dto_helper'
8
+
9
+ # reference: https://github.com/sqreen/SignalsSchemas/blob/master/schemas/payload/sqreen_exception/2020-01-01T00_00_00_000Z/schema.cue
10
+
11
+ module Sqreen
12
+ module Kit
13
+ module Signals
14
+ module Specialized
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ class Sqreen::Kit::Signals::Specialized::SqreenException < Sqreen::Kit::Signals::Point
21
+ PAYLOAD_SCHEMA_VERSION = 'sqreen_exception/2020-01-01T00:00:00.000Z'.freeze
22
+
23
+ # @return [Hash]
24
+ attr_accessor :infos
25
+
26
+ # @return [Exception]
27
+ attr_accessor :ruby_exception
28
+
29
+ add_mandatory_attrs :source, :time, :ruby_exception
30
+
31
+ validate_str_attr :source, /\A(?:sqreen:rule:[a-f0-9]{40}:.+)|(?:sqreen:agent:.+)\z/
32
+
33
+ def self.attributes_for_to_h_self
34
+ [] # don't include ruby_exception in list of attributes for to_h
35
+ end
36
+
37
+ def initialize(values = {})
38
+ self.payload_schema = PAYLOAD_SCHEMA_VERSION
39
+ self.signal_name = 'sq.agent.exception'
40
+ self.time = values[:time] || Time.now
41
+ super
42
+ end
43
+
44
+ def payload
45
+ return nil unless @ruby_exception
46
+ compact_hash({
47
+ klass: @ruby_exception.class.to_s,
48
+ message: @ruby_exception.message,
49
+ infos: @infos,
50
+ })
51
+ end
52
+
53
+ def location
54
+ return nil unless @ruby_exception
55
+ Sqreen::Kit::Signals::Location.new(exception: @ruby_exception)
56
+ end
57
+ end
@@ -0,0 +1,221 @@
1
+ # typed: ignore
2
+
3
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
+
6
+ require 'sqreen/aggregated_metric'
7
+ require 'sqreen/log/loggable'
8
+ require 'sqreen/legacy/waf_redactions'
9
+
10
+ module Sqreen
11
+ module Legacy
12
+ # see also Sqreen::Signals::SignalsSubmissionStrategy
13
+ # usage in Sqreen:Session
14
+ class OldEventSubmissionStrategy
15
+ include Sqreen::Log::Loggable
16
+
17
+ RETRY_MANY = 301
18
+
19
+ def initialize(post_proc)
20
+ @post_proc = post_proc
21
+ end
22
+
23
+ def post_metrics(metrics)
24
+ return if metrics.nil? || metrics.empty?
25
+ payload = { metrics: metrics.map { |m| EventToHash.convert_agg_metric(m) } }
26
+ post('metrics', payload, {}, RETRY_MANY)
27
+ end
28
+
29
+ # @param attack [Sqreen::Attack]
30
+ def post_attack(attack)
31
+ post('attack', EventToHash.convert_attack(attack), {}, RETRY_MANY)
32
+ end
33
+
34
+ # @param [Sqreen::RequestRecord] request_record
35
+ def post_request_record(request_record)
36
+ rr_hash = EventToHash.convert_request_record(request_record)
37
+ post('request_record', rr_hash, {}, RETRY_MANY)
38
+ end
39
+
40
+ # Post an exception to Sqreen for analysis
41
+ # @param exception [RemoteException] Exception and context to be sent over
42
+ def post_sqreen_exception(exception)
43
+ data = EventToHash.convert_exception(exception)
44
+ post('sqreen_exception', data, {}, 5)
45
+ rescue StandardError => e
46
+ logger.warn(format('Could not post exception (network down? %s) %s',
47
+ e.inspect,
48
+ exception.inspect))
49
+ nil
50
+ end
51
+
52
+ def post_batch(events)
53
+ batch = events.map do |event|
54
+ h = case event
55
+ when AggregatedMetric
56
+ logger.warn "Aggregated metric event in non-signal mode. Signals disabled at runtime?"
57
+ next
58
+ when Attack # in practice only found inside req rec
59
+ EventToHash.convert_attack event
60
+ when RemoteException
61
+ EventToHash.convert_exception event
62
+ when RequestRecord
63
+ EventToHash.convert_request_record event
64
+ else
65
+ logger.warn "Unexpected event type: #{event}"
66
+ next
67
+ end
68
+ h['event_type'] = event_kind(event)
69
+ h
70
+ end
71
+ Sqreen.log.debug do
72
+ tally = Hash[events.group_by(&:class).map { |k, v| [k, v.count] }]
73
+ "Doing batch with the following tally of event types: #{tally}"
74
+ end
75
+ post('batch', { batch: batch }, {}, RETRY_MANY)
76
+ end
77
+
78
+ private
79
+
80
+ # see +Sqreen::Session.post+
81
+ def post(*args)
82
+ @post_proc[*args]
83
+ end
84
+
85
+ def event_kind(event)
86
+ case event
87
+ when Sqreen::RemoteException then 'sqreen_exception'
88
+ when Sqreen::Attack then 'attack'
89
+ when Sqreen::RequestRecord then 'request_record'
90
+ end
91
+ end
92
+ end
93
+
94
+ module EventToHash
95
+ class << self
96
+ # @param attack [Sqreen::Attack]
97
+ def convert_attack(attack)
98
+ payload = attack.payload
99
+ res = {}
100
+ rule_p = payload['rule']
101
+ request_p = payload['request']
102
+ res[:rule_name] = rule_p['name'] if rule_p && rule_p['name']
103
+ res[:rulespack_id] = rule_p['rulespack_id'] if rule_p && rule_p['rulespack_id']
104
+ res[:test] = rule_p['test'] if rule_p && rule_p['test']
105
+ res[:infos] = payload['infos'] if payload['infos']
106
+ res[:time] = attack.time
107
+ res[:client_ip] = request_p[:addr] if request_p && request_p[:addr]
108
+ res[:request] = request_p if request_p
109
+ res[:params] = payload['params'] if payload['params']
110
+ res[:context] = payload['context'] if payload['context']
111
+ res[:headers] = payload['headers'] if payload['headers']
112
+ res
113
+ end
114
+
115
+ # @param [Sqreen::RequestRecord] rr
116
+ def convert_request_record(rr)
117
+ res = { :version => '20171208' }
118
+ payload = rr.payload
119
+
120
+ if payload[:observed]
121
+ res[:observed] = payload[:observed].dup
122
+ rulespack = nil
123
+ if rr.observed[:attacks]
124
+ res[:observed][:attacks] = rr.observed[:attacks].map do |att|
125
+ natt = att.dup
126
+ [:attack_type, :block].each { |k| natt.delete(k) } # signals stuff
127
+ rulespack = natt.delete(:rulespack_id) || rulespack
128
+ natt
129
+ end
130
+ end
131
+ if rr.observed[:sqreen_exceptions]
132
+ res[:observed][:sqreen_exceptions] = rr.observed[:sqreen_exceptions].map do |exc|
133
+ nex = exc.dup
134
+ excp = nex.delete(:exception)
135
+ if excp
136
+ nex[:message] = excp.message
137
+ nex[:klass] = excp.class.name
138
+ end
139
+ rulespack = nex.delete(:rulespack_id) || rulespack
140
+ nex
141
+ end
142
+ end
143
+ res[:rulespack_id] = rulespack unless rulespack.nil?
144
+ if rr.observed[:observations]
145
+ res[:observed][:observations] = rr.observed[:observations].map do |cat, key, value, time|
146
+ { :category => cat, :key => key, :value => value, :time => time }
147
+ end
148
+ end
149
+ if rr.observed[:sdk] # rubocop:disable Style/IfUnlessModifier
150
+ res[:observed][:sdk] = rr.processed_sdk_calls
151
+ end
152
+ end
153
+ res[:local] = payload['local'] if payload['local']
154
+ if payload['request']
155
+ res[:request] = payload['request'].dup
156
+ res[:client_ip] = res[:request].delete(:client_ip) if res[:request][:client_ip]
157
+ else
158
+ res[:request] = {}
159
+ end
160
+ if payload['response']
161
+ res[:response] = payload['response'].dup
162
+ else
163
+ res[:response] = {}
164
+ end
165
+
166
+ res[:request][:parameters] = payload['params'] if payload['params']
167
+ res[:request][:headers] = payload['headers'] if payload['headers']
168
+
169
+ res = Sqreen::EncodingSanitizer.sanitize(res)
170
+
171
+ if rr.redactor
172
+ res[:request], redacted = rr.redactor.redact(res[:request])
173
+ redacted = redacted.uniq
174
+ if redacted.any? && res[:observed] && res[:observed][:attacks]
175
+ res[:observed][:attacks] = WafRedactions.redact_attacks!(res[:observed][:attacks], redacted)
176
+ end
177
+ if redacted.any? && res[:observed] && res[:observed][:sqreen_exceptions]
178
+ res[:observed][:sqreen_exceptions] = WafRedactions.redact_exceptions!(res[:observed][:sqreen_exceptions], redacted)
179
+ end
180
+ end
181
+
182
+ res
183
+ end
184
+
185
+ # @param exception_evt [Sqreen::RemoteException]
186
+ def convert_exception(exception_evt)
187
+ payload = exception_evt.payload
188
+ exception = payload['exception']
189
+ ev = {
190
+ :klass => exception.class.name,
191
+ :message => exception.message,
192
+ :params => payload['request_params'],
193
+ :time => payload['time'],
194
+ :infos => {
195
+ :client_ip => payload['client_ip'],
196
+ },
197
+ :request => payload['request_infos'],
198
+ :headers => payload['headers'],
199
+ :rule_name => payload['rule_name'],
200
+ :rulespack_id => payload['rulespack_id'],
201
+ }
202
+
203
+ ev[:infos].merge!(payload['infos']) if payload['infos']
204
+ return ev unless exception.backtrace
205
+ ev[:context] = { :backtrace => exception.backtrace.map(&:to_s) }
206
+ ev
207
+ end
208
+
209
+ # @param [Sqreen::AggregatedMetric] agg_metric
210
+ def convert_agg_metric(agg_metric)
211
+ {
212
+ name: agg_metric.name,
213
+ observation: agg_metric.data,
214
+ start: agg_metric.start,
215
+ finish: agg_metric.finish,
216
+ }
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end