sqreen 1.19.3-java → 1.20.0-java

Sign up to get free protection for your applications and to get access to all the features.
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