sqreen 1.20.1-java → 1.20.4-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.
- checksums.yaml +5 -5
- data/CHANGELOG.md +25 -0
- data/lib/sqreen/actions/block_user.rb +1 -1
- data/lib/sqreen/actions/redirect_ip.rb +1 -1
- data/lib/sqreen/actions/redirect_user.rb +1 -1
- data/lib/sqreen/attack_detected.html +1 -2
- data/lib/sqreen/condition_evaluator.rb +8 -2
- data/lib/sqreen/configuration.rb +1 -1
- data/lib/sqreen/deferred_logger.rb +50 -14
- data/lib/sqreen/deprecation.rb +38 -0
- data/lib/sqreen/events/request_record.rb +0 -1
- data/lib/sqreen/frameworks/generic.rb +9 -0
- data/lib/sqreen/frameworks/rails.rb +0 -7
- data/lib/sqreen/frameworks/request_recorder.rb +2 -0
- data/lib/sqreen/graft/call.rb +76 -18
- data/lib/sqreen/graft/callback.rb +1 -1
- data/lib/sqreen/graft/hook.rb +187 -85
- data/lib/sqreen/graft/hook_point.rb +1 -1
- data/lib/sqreen/legacy/instrumentation.rb +22 -10
- data/lib/sqreen/legacy/old_event_submission_strategy.rb +2 -1
- data/lib/sqreen/log.rb +3 -2
- data/lib/sqreen/log/loggable.rb +1 -0
- data/lib/sqreen/logger.rb +24 -0
- data/lib/sqreen/metrics_store.rb +11 -0
- data/lib/sqreen/null_logger.rb +22 -0
- data/lib/sqreen/remote_command.rb +1 -0
- data/lib/sqreen/rules.rb +8 -4
- data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
- data/lib/sqreen/rules/custom_error_cb.rb +3 -3
- data/lib/sqreen/rules/rule_cb.rb +2 -0
- data/lib/sqreen/rules/waf_cb.rb +3 -3
- data/lib/sqreen/runner.rb +28 -2
- data/lib/sqreen/version.rb +1 -1
- data/lib/sqreen/weave/budget.rb +46 -0
- data/lib/sqreen/weave/legacy/instrumentation.rb +194 -103
- data/lib/sqreen/worker.rb +6 -2
- metadata +7 -6
- data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -6,6 +6,7 @@
|
|
6
6
|
require 'sqreen/aggregated_metric'
|
7
7
|
require 'sqreen/log/loggable'
|
8
8
|
require 'sqreen/legacy/waf_redactions'
|
9
|
+
require 'sqreen/kit/string_sanitizer'
|
9
10
|
|
10
11
|
module Sqreen
|
11
12
|
module Legacy
|
@@ -166,7 +167,7 @@ module Sqreen
|
|
166
167
|
res[:request][:parameters] = payload['params'] if payload['params']
|
167
168
|
res[:request][:headers] = payload['headers'] if payload['headers']
|
168
169
|
|
169
|
-
res = Sqreen::
|
170
|
+
res = Sqreen::Kit::StringSanitizer.sanitize(res)
|
170
171
|
|
171
172
|
if rr.redactor
|
172
173
|
res[:request], redacted = rr.redactor.redact(res[:request])
|
data/lib/sqreen/log.rb
CHANGED
@@ -14,16 +14,17 @@ require 'sqreen/deferred_logger'
|
|
14
14
|
|
15
15
|
module Sqreen
|
16
16
|
def self.log_init
|
17
|
+
deferred_logger = @logger
|
17
18
|
@logger = Sqreen::Logger.new(
|
18
19
|
Sqreen.config_get(:log_level).to_s.upcase,
|
19
20
|
Sqreen.config_get(:log_location)
|
20
21
|
)
|
21
|
-
|
22
|
+
deferred_logger.flush_to(@logger.instance_eval { @logger })
|
22
23
|
rescue => e
|
23
24
|
warn "Sqreen logger exception: #{e}"
|
24
25
|
end
|
25
26
|
|
26
27
|
def self::log
|
27
|
-
@logger
|
28
|
+
@logger ||= Sqreen::DeferredLogger.new
|
28
29
|
end
|
29
30
|
end
|
data/lib/sqreen/log/loggable.rb
CHANGED
data/lib/sqreen/logger.rb
CHANGED
@@ -28,6 +28,26 @@ module Sqreen
|
|
28
28
|
create_error_logger
|
29
29
|
end
|
30
30
|
|
31
|
+
def debug?
|
32
|
+
@logger.debug?
|
33
|
+
end
|
34
|
+
|
35
|
+
def info?
|
36
|
+
@logger.info?
|
37
|
+
end
|
38
|
+
|
39
|
+
def warn?
|
40
|
+
@logger.warn?
|
41
|
+
end
|
42
|
+
|
43
|
+
def error?
|
44
|
+
@logger.error?
|
45
|
+
end
|
46
|
+
|
47
|
+
def fatal?
|
48
|
+
@logger.fatal?
|
49
|
+
end
|
50
|
+
|
31
51
|
def debug(msg = nil, &block)
|
32
52
|
@logger.debug(msg, &block)
|
33
53
|
end
|
@@ -45,6 +65,10 @@ module Sqreen
|
|
45
65
|
@logger.error(msg, &block)
|
46
66
|
end
|
47
67
|
|
68
|
+
def unknown(msg = nil, &block)
|
69
|
+
@logger.unknown(msg, &block)
|
70
|
+
end
|
71
|
+
|
48
72
|
def add(severity, msg = nil, &block)
|
49
73
|
send(SEVERITY_TO_METHOD[severity], msg, &block)
|
50
74
|
end
|
data/lib/sqreen/metrics_store.rb
CHANGED
@@ -27,6 +27,7 @@ module Sqreen
|
|
27
27
|
def initialize
|
28
28
|
@store = []
|
29
29
|
@metrics = {} # name => (metric, period, start)
|
30
|
+
@mutex = Mutex.new
|
30
31
|
end
|
31
32
|
|
32
33
|
# Definition contains a name,period and aggregate at least
|
@@ -34,6 +35,8 @@ module Sqreen
|
|
34
35
|
# @param rule [RuleCB] the rule associated with this metric, if any
|
35
36
|
# @param mklass [Object] Override metric object (used in testing)
|
36
37
|
def create_metric(definition, rule = nil, mklass = nil)
|
38
|
+
@mutex.lock
|
39
|
+
|
37
40
|
name = definition[NAME_KEY]
|
38
41
|
kind = definition[KIND_KEY]
|
39
42
|
klass = valid_metric(kind, name)
|
@@ -49,6 +52,8 @@ module Sqreen
|
|
49
52
|
metric.rule = rule
|
50
53
|
metric.period = definition[PERIOD_KEY]
|
51
54
|
metric
|
55
|
+
ensure
|
56
|
+
@mutex.unlock
|
52
57
|
end
|
53
58
|
|
54
59
|
def metric?(name)
|
@@ -57,21 +62,27 @@ module Sqreen
|
|
57
62
|
|
58
63
|
# @param at [Time] when is the store emptied
|
59
64
|
def update(name, at, key, value)
|
65
|
+
@mutex.lock
|
60
66
|
metric, period, start = @metrics[name]
|
61
67
|
raise UnregisteredMetric, "Unknown metric #{name}" unless metric
|
62
68
|
next_sample(name, at) if start.nil? || (start + period) < at
|
63
69
|
metric.update(key, value)
|
70
|
+
ensure
|
71
|
+
@mutex.unlock
|
64
72
|
end
|
65
73
|
|
66
74
|
# Drains every metrics and returns the store content
|
67
75
|
# @param at [Time] when is the store emptied
|
68
76
|
def publish(flush = true, at = Sqreen.time)
|
77
|
+
@mutex.lock
|
69
78
|
@metrics.each do |name, (_, period, start)|
|
70
79
|
next_sample(name, at) if flush || !start.nil? && (start + period) < at
|
71
80
|
end
|
72
81
|
out = @store
|
73
82
|
@store = []
|
74
83
|
out
|
84
|
+
ensure
|
85
|
+
@mutex.unlock
|
75
86
|
end
|
76
87
|
|
77
88
|
protected
|
data/lib/sqreen/null_logger.rb
CHANGED
@@ -9,6 +9,26 @@ module Sqreen
|
|
9
9
|
class NullLogger
|
10
10
|
include Singleton
|
11
11
|
|
12
|
+
def debug?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def info?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def warn?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def error?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def fatal?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
12
32
|
def debug(_msg = nil); end
|
13
33
|
|
14
34
|
def info(_msg = nil); end
|
@@ -19,6 +39,8 @@ module Sqreen
|
|
19
39
|
|
20
40
|
def fatal(_msg = nil); end
|
21
41
|
|
42
|
+
def unknown(_msg = nil); end
|
43
|
+
|
22
44
|
def add(_severity, _msg = nil); end
|
23
45
|
|
24
46
|
def formatter=(_); end
|
@@ -18,6 +18,7 @@ module Sqreen
|
|
18
18
|
:features_get => :features,
|
19
19
|
:features_change => :change_features,
|
20
20
|
:force_logout => :shutdown,
|
21
|
+
:force_restart => :restart,
|
21
22
|
:paths_whitelist => :change_whitelisted_paths,
|
22
23
|
:ips_whitelist => :change_whitelisted_ips,
|
23
24
|
:get_bundle => :upload_bundle,
|
data/lib/sqreen/rules.rb
CHANGED
@@ -114,15 +114,19 @@ module Sqreen
|
|
114
114
|
Sqreen.log.warn('No JavaScript engine is available. ' \
|
115
115
|
'JavaScript callbacks will be ignored')
|
116
116
|
end
|
117
|
-
Sqreen.log.
|
117
|
+
Sqreen.log.debug("Ignoring JS callback #{rule_name}")
|
118
118
|
return nil
|
119
119
|
end
|
120
120
|
|
121
121
|
cb_class = ExecJSCB if js
|
122
122
|
|
123
|
-
if cbname
|
124
|
-
|
125
|
-
|
123
|
+
if cbname
|
124
|
+
cb_class = if cbname.include?('::')
|
125
|
+
# Only load callbacks from sqreen
|
126
|
+
Rules.walk_const_get(cbname) if cbname.start_with?('::Sqreen::', 'Sqreen::')
|
127
|
+
else
|
128
|
+
Rules.const_get(cbname) if Rules.const_defined?(cbname) # rubocop:disable Style/IfInsideElse
|
129
|
+
end
|
126
130
|
end
|
127
131
|
|
128
132
|
if cb_class.nil?
|
@@ -33,7 +33,7 @@ module Sqreen
|
|
33
33
|
private
|
34
34
|
|
35
35
|
def insert_values(ranges)
|
36
|
-
Sqreen.log.
|
36
|
+
Sqreen.log.debug 'no ips given for IP blacklisting' if ranges.empty?
|
37
37
|
|
38
38
|
ranges.map { |r| Prefix.from_str(r, r) }.each do |prefix|
|
39
39
|
trie_for(prefix).insert prefix
|
@@ -50,7 +50,7 @@ module Sqreen
|
|
50
50
|
begin
|
51
51
|
ipa = IPAddr.new(rip)
|
52
52
|
rescue StandardError
|
53
|
-
Sqreen.log.
|
53
|
+
Sqreen.log.debug "invalid IP address given by framework: #{rip}"
|
54
54
|
return nil
|
55
55
|
end
|
56
56
|
|
@@ -55,12 +55,12 @@ module Sqreen
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def respond_page
|
58
|
-
page
|
58
|
+
@page ||= File.read(File.join(File.dirname(__FILE__), '../attack_detected.html'))
|
59
59
|
headers = {
|
60
60
|
'Content-Type' => 'text/html',
|
61
|
-
'Content-Length' => page.size.to_s,
|
61
|
+
'Content-Length' => @page.size.to_s,
|
62
62
|
}
|
63
|
-
[@status_code, headers, page]
|
63
|
+
[@status_code, headers, [@page]]
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
data/lib/sqreen/rules/rule_cb.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
# Copyright (c) 2015 Sqreen. All Rights Reserved.
|
4
4
|
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
5
|
|
6
|
+
require 'sqreen/deprecation'
|
6
7
|
require 'sqreen/framework_cb'
|
7
8
|
require 'sqreen/context'
|
8
9
|
require 'sqreen/conditionable'
|
@@ -109,6 +110,7 @@ module Sqreen
|
|
109
110
|
)
|
110
111
|
true
|
111
112
|
end
|
113
|
+
Sqreen::Deprecation.deprecate(instance_method(:overtime!))
|
112
114
|
end
|
113
115
|
end
|
114
116
|
end
|
data/lib/sqreen/rules/waf_cb.rb
CHANGED
@@ -11,7 +11,7 @@ require 'sqreen/safe_json'
|
|
11
11
|
require 'sqreen/exception'
|
12
12
|
require 'sqreen/util/capper'
|
13
13
|
require 'sqreen/dependency/libsqreen'
|
14
|
-
require 'sqreen/
|
14
|
+
require 'sqreen/kit/string_sanitizer'
|
15
15
|
|
16
16
|
module Sqreen
|
17
17
|
module Rules
|
@@ -60,7 +60,7 @@ module Sqreen
|
|
60
60
|
end
|
61
61
|
|
62
62
|
# 0 for using defaults (PW_RUN_TIMEOUT)
|
63
|
-
@max_run_budget_us = (@data['values'].fetch('
|
63
|
+
@max_run_budget_us = (@data['values'].fetch('max_budget_ms', 0) * 1000).to_i
|
64
64
|
@max_run_budget_us = INFINITE_BUDGET_US if @max_run_budget_us >= INFINITE_BUDGET_US
|
65
65
|
|
66
66
|
Sqreen.log.debug { "Max WAF run budget for #{@waf_rule_name} set to #{@max_run_budget_us} us" }
|
@@ -82,7 +82,7 @@ module Sqreen
|
|
82
82
|
waf_args = binding_accessors.each_with_object({}) do |(e, b), h|
|
83
83
|
h[e] = capper.call(b.resolve(*env))
|
84
84
|
end
|
85
|
-
waf_args = Sqreen::
|
85
|
+
waf_args = Sqreen::Kit::StringSanitizer.sanitize(waf_args)
|
86
86
|
|
87
87
|
if budget
|
88
88
|
rem_budget_s = budget - (Sqreen.time - start)
|
data/lib/sqreen/runner.rb
CHANGED
@@ -387,8 +387,25 @@ module Sqreen
|
|
387
387
|
|
388
388
|
def change_performance_budget(budget, _context_infos = {})
|
389
389
|
return false unless budget.nil? || budget.to_f > 0
|
390
|
-
|
391
|
-
|
390
|
+
|
391
|
+
if @configuration.get(:weave)
|
392
|
+
prev = Sqreen::Weave::Budget.current
|
393
|
+
prev = prev.to_h if prev
|
394
|
+
|
395
|
+
budget_s = budget.to_f / 1000 if budget
|
396
|
+
|
397
|
+
feature = features['performance_budget']
|
398
|
+
if feature
|
399
|
+
budget_s = feature['threshold'] if feature.key?('threshold')
|
400
|
+
ratio = feature['ratio'] if feature.key?('ratio')
|
401
|
+
end
|
402
|
+
|
403
|
+
Sqreen::Weave::Budget.update(threshold: budget_s, ratio: ratio)
|
404
|
+
else
|
405
|
+
prev = Sqreen.performance_budget
|
406
|
+
Sqreen.update_performance_budget(budget)
|
407
|
+
end
|
408
|
+
|
392
409
|
{ :was => prev }
|
393
410
|
end
|
394
411
|
|
@@ -478,6 +495,15 @@ module Sqreen
|
|
478
495
|
logout
|
479
496
|
end
|
480
497
|
|
498
|
+
def restart(_context_infos = {})
|
499
|
+
shutdown
|
500
|
+
heartbeat_delay = @heartbeat_delay
|
501
|
+
Thread.new do
|
502
|
+
sleep(2 * heartbeat_delay)
|
503
|
+
Sqreen::Worker.start(Sqreen.framework)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
481
507
|
def logout(retrying = true)
|
482
508
|
return unless session
|
483
509
|
Sqreen.log.debug("Logging out")
|
data/lib/sqreen/version.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
1
|
+
# typed: false
|
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/log/loggable'
|
7
|
+
require 'sqreen/weave'
|
8
|
+
|
9
|
+
class Sqreen::Weave::Budget
|
10
|
+
include Sqreen::Log::Loggable
|
11
|
+
|
12
|
+
def initialize(threshold, ratio = nil)
|
13
|
+
@threshold = threshold
|
14
|
+
@ratio = ratio
|
15
|
+
end
|
16
|
+
|
17
|
+
def static?
|
18
|
+
threshold && !ratio
|
19
|
+
end
|
20
|
+
|
21
|
+
def dynamic?
|
22
|
+
threshold && ratio
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :threshold
|
26
|
+
attr_reader :ratio
|
27
|
+
|
28
|
+
def to_h
|
29
|
+
{ threshold: threshold, ratio: ratio }
|
30
|
+
end
|
31
|
+
|
32
|
+
class << self
|
33
|
+
attr_reader :current
|
34
|
+
|
35
|
+
def update(opts = nil)
|
36
|
+
Sqreen::Weave.logger.info("budget update:#{opts.inspect}")
|
37
|
+
|
38
|
+
return @current = nil if opts.nil? || opts.empty?
|
39
|
+
|
40
|
+
threshold = opts[:threshold]
|
41
|
+
ratio = opts[:ratio]
|
42
|
+
|
43
|
+
@current = new(threshold, ratio)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -4,10 +4,13 @@
|
|
4
4
|
# Please refer to our terms for more information: https://www.sqreen.com/terms.html
|
5
5
|
|
6
6
|
require 'sqreen/weave/legacy'
|
7
|
+
require 'sqreen/weave/budget'
|
8
|
+
require 'sqreen/graft/hook'
|
7
9
|
require 'sqreen/graft/hook_point'
|
8
10
|
require 'sqreen/call_countable'
|
9
11
|
require 'sqreen/rules'
|
10
12
|
require 'sqreen/rules/record_request_context'
|
13
|
+
require 'sqreen/sqreen_signed_verifier'
|
11
14
|
|
12
15
|
class Sqreen::Weave::Legacy::Instrumentation
|
13
16
|
attr_accessor :metrics_engine
|
@@ -60,6 +63,27 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
60
63
|
'options' => opts[:perf_metric_percent] || { 'base' => 1.3, 'factor' => 1.0 },
|
61
64
|
)
|
62
65
|
|
66
|
+
metrics_engine.create_metric(
|
67
|
+
'name' => 'req.sq.hook.overhead',
|
68
|
+
'period' => 60,
|
69
|
+
'kind' => 'Binning',
|
70
|
+
'options' => { 'base' => 2.0, 'factor' => 0.1 },
|
71
|
+
)
|
72
|
+
|
73
|
+
metrics_engine.create_metric(
|
74
|
+
'name' => 'sq.hook.overhead',
|
75
|
+
'period' => 60,
|
76
|
+
'kind' => 'Binning',
|
77
|
+
'options' => { 'base' => 2.0, 'factor' => 0.1 },
|
78
|
+
)
|
79
|
+
|
80
|
+
metrics_engine.create_metric(
|
81
|
+
'name' => 'sq.shrinkwrap',
|
82
|
+
'period' => 60,
|
83
|
+
'kind' => 'Binning',
|
84
|
+
'options' => { 'base' => 2.0, 'factor' => 0.1 },
|
85
|
+
)
|
86
|
+
|
63
87
|
Sqreen.thread_cpu_time? && metrics_engine.create_metric(
|
64
88
|
'name' => 'sq_thread_cpu_pct',
|
65
89
|
'period' => opts[:period] || 60,
|
@@ -84,6 +108,15 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
84
108
|
|
85
109
|
### set up rule signature verifier
|
86
110
|
verifier = nil
|
111
|
+
if Sqreen.features['rules_signature'] &&
|
112
|
+
Sqreen.config_get(:rules_verify_signature) == true &&
|
113
|
+
!defined?(::JRUBY_VERSION)
|
114
|
+
verifier = Sqreen::SqreenSignedVerifier.new
|
115
|
+
Sqreen::Weave.logger.debug('Rules signature enabled')
|
116
|
+
else
|
117
|
+
Sqreen::Weave.logger.debug('Rules signature disabled')
|
118
|
+
end
|
119
|
+
|
87
120
|
### force clean instrumentation callback list
|
88
121
|
@hooks = []
|
89
122
|
### for each rule description
|
@@ -94,6 +127,25 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
94
127
|
next unless rule_callback
|
95
128
|
### attach framework to callback
|
96
129
|
rule_callback.framework = framework
|
130
|
+
## create metric
|
131
|
+
Sqreen::Weave.logger.debug { "Adding rule metric: #{rule_callback}" }
|
132
|
+
[:pre, :post, :failing].each do |whence|
|
133
|
+
next unless rule_callback.send(:"#{whence}?")
|
134
|
+
metric_name = "sq.#{rule['name']}.#{whence}"
|
135
|
+
metrics_engine.create_metric(
|
136
|
+
'name' => metric_name,
|
137
|
+
'period' => 60,
|
138
|
+
'kind' => 'Binning',
|
139
|
+
'options' => { 'base' => 2.0, 'factor' => 0.1 },
|
140
|
+
)
|
141
|
+
metric_name = "req.sq.#{rule['name']}.#{whence}"
|
142
|
+
metrics_engine.create_metric(
|
143
|
+
'name' => metric_name,
|
144
|
+
'period' => 60,
|
145
|
+
'kind' => 'Binning',
|
146
|
+
'options' => { 'base' => 2.0, 'factor' => 0.1 },
|
147
|
+
)
|
148
|
+
end
|
97
149
|
### install callback, observing priority
|
98
150
|
Sqreen::Weave.logger.debug { "Adding rule callback: #{rule_callback}" }
|
99
151
|
@hooks << add_callback("weave,rule=#{rule['name']}", rule_callback, strategy)
|
@@ -107,30 +159,43 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
107
159
|
end
|
108
160
|
|
109
161
|
metrics_engine = self.metrics_engine
|
162
|
+
|
110
163
|
request_hook = Sqreen::Graft::Hook['Sqreen::ShrinkWrap#call', strategy]
|
111
164
|
@hooks << request_hook
|
112
165
|
request_hook.add do
|
113
166
|
before('wave,meta,request', rank: -100000, mandatory: true) do |_call|
|
114
167
|
next unless Sqreen.instrumentation_ready
|
115
168
|
|
116
|
-
|
117
|
-
|
169
|
+
# shrinkwrap_timer = Sqreen::Graft::Timer.new('weave,shrinkwrap')
|
170
|
+
# shrinkwrap_timer.start
|
171
|
+
|
172
|
+
request_timer = Sqreen::Graft::Timer.new("request")
|
173
|
+
request_timer.start
|
174
|
+
sqreen_timer = Sqreen::Graft::Timer.new("sqreen")
|
175
|
+
budget = Sqreen::Weave::Budget.current
|
176
|
+
request_budget_threshold = budget.threshold if budget
|
177
|
+
request_budget_ratio = budget.ratio if budget
|
178
|
+
request_budget_is_dynamic = !request_budget_ratio.nil?
|
179
|
+
request_budget = !request_budget_threshold.nil?
|
180
|
+
timed_level = (Sqreen.features['perf_level'] || 1).to_i
|
181
|
+
Sqreen::Weave.logger.debug { "request budget: #{budget.to_h} timed.level: #{timed_level}" } if Sqreen::Weave.logger.debug?
|
182
|
+
|
118
183
|
Thread.current[:sqreen_http_request] = {
|
119
|
-
|
120
|
-
|
121
|
-
time_budget: Sqreen.performance_budget,
|
184
|
+
request_timer: request_timer,
|
185
|
+
sqreen_timer: sqreen_timer,
|
122
186
|
time_budget_expended: false,
|
123
|
-
|
187
|
+
time_budget_threshold: request_budget_threshold,
|
188
|
+
time_budget_dynamic: request_budget_is_dynamic,
|
189
|
+
time_budget_ratio: request_budget_ratio,
|
190
|
+
time_budget: request_budget,
|
124
191
|
timed_callbacks: [],
|
125
192
|
timed_hooks: [],
|
126
|
-
|
127
|
-
timed_hooks_after: [],
|
128
|
-
timed_hooks_raised: [],
|
129
|
-
timed_hooks_ensured: [],
|
193
|
+
timed_level: timed_level,
|
130
194
|
skipped_callbacks: [],
|
195
|
+
# timed_shrinkwrap: shrinkwrap_timer,
|
131
196
|
}
|
132
197
|
|
133
|
-
|
198
|
+
# shrinkwrap_timer.stop
|
134
199
|
end
|
135
200
|
|
136
201
|
ensured('weave,meta,request', rank: 100000, mandatory: true) do |_call|
|
@@ -138,105 +203,118 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
138
203
|
|
139
204
|
next if request.nil?
|
140
205
|
|
206
|
+
# shrinkwrap_timer = request[:timed_shrinkwrap]
|
207
|
+
# shrinkwrap_timer.start
|
208
|
+
|
141
209
|
Thread.current[:sqreen_http_request] = nil
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
request[:
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
metrics_engine.
|
161
|
-
|
162
|
-
'period' => 60,
|
163
|
-
'kind' => 'Binning',
|
164
|
-
'options' => { 'base' => 2.0, 'factor' => 0.1 },
|
165
|
-
)
|
210
|
+
request_timer = request[:request_timer]
|
211
|
+
now = request_timer.stop
|
212
|
+
|
213
|
+
if request[:timed_level] >= 1
|
214
|
+
request[:timed_callbacks].each do |timer|
|
215
|
+
duration = timer.duration
|
216
|
+
|
217
|
+
timer.tag =~ /weave,rule=(.*)$/ && rule = $1
|
218
|
+
next unless rule
|
219
|
+
|
220
|
+
whence = case timer.tag
|
221
|
+
when /@before/ then 'pre'
|
222
|
+
when /@after/ then 'post'
|
223
|
+
when /@raised/ then 'failing'
|
224
|
+
end
|
225
|
+
next unless whence
|
226
|
+
|
227
|
+
metric_name = "sq.#{rule}.#{whence}"
|
228
|
+
metrics_engine.update(metric_name, now, nil, duration * 1000)
|
229
|
+
# Sqreen.observations_queue.push([metric_name, nil, duration * 1000, utc_now])
|
166
230
|
end
|
167
|
-
metrics_engine.update(metric_name, now, nil, duration * 1000)
|
168
|
-
end
|
169
231
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
'period' => 60,
|
176
|
-
'kind' => 'Binning',
|
177
|
-
'options' => { 'base' => 2.0, 'factor' => 0.1 },
|
178
|
-
)
|
179
|
-
end
|
180
|
-
metrics_engine.update(metric_name, now, nil, duration * 1000)
|
181
|
-
|
182
|
-
metric_name = 'sq.hooks_post.post'
|
183
|
-
duration = request[:timed_hooks_after].sum(&:duration)
|
184
|
-
unless metrics_engine.metric?(metric_name)
|
185
|
-
metrics_engine.create_metric(
|
186
|
-
'name' => metric_name,
|
187
|
-
'period' => 60,
|
188
|
-
'kind' => 'Binning',
|
189
|
-
'options' => { 'base' => 2.0, 'factor' => 0.1 },
|
190
|
-
)
|
191
|
-
end
|
192
|
-
metrics_engine.update(metric_name, now, nil, duration * 1000)
|
193
|
-
|
194
|
-
metric_name = 'sq.hooks_failing.failing'
|
195
|
-
duration = request[:timed_hooks_raised].sum(&:duration)
|
196
|
-
unless metrics_engine.metric?(metric_name)
|
197
|
-
metrics_engine.create_metric(
|
198
|
-
'name' => metric_name,
|
199
|
-
'period' => 60,
|
200
|
-
'kind' => 'Binning',
|
201
|
-
'options' => { 'base' => 2.0, 'factor' => 0.1 },
|
202
|
-
)
|
232
|
+
request[:timed_hooks].each do |timer|
|
233
|
+
duration = timer.duration
|
234
|
+
metrics_engine.update('sq.hook.overhead', now, nil, duration * 1000)
|
235
|
+
# Sqreen.observations_queue.push(['sq.hook.overhead', nil, duration * 1000, utc_now])
|
236
|
+
end
|
203
237
|
end
|
204
|
-
metrics_engine.update(metric_name, now, nil, duration * 1000)
|
205
238
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
total =
|
210
|
-
Sqreen::Weave.logger.debug { "request
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
239
|
+
sqreen_timer = request[:sqreen_timer]
|
240
|
+
total = sqreen_timer.duration
|
241
|
+
Sqreen::Weave.logger.debug { "request sqreen_timer.total: #{'%.03fus' % (total * 1_000_000)}" } if Sqreen::Weave.logger.debug?
|
242
|
+
total = request_timer.duration
|
243
|
+
Sqreen::Weave.logger.debug { "request request_timer.total: #{'%.03fus' % (total * 1_000_000)}" } if Sqreen::Weave.logger.debug?
|
244
|
+
|
245
|
+
if request[:timed_level] >= 2
|
246
|
+
skipped = request[:skipped_callbacks].map(&:name)
|
247
|
+
Sqreen::Weave.logger.debug { "request callback.skipped.count: #{skipped.count}" } if Sqreen::Weave.logger.debug?
|
248
|
+
timings = request[:timed_callbacks].map(&:to_s)
|
249
|
+
total = request[:timed_callbacks].sum(&:duration)
|
250
|
+
Sqreen::Weave.logger.debug { "request callback.total: #{'%.03fus' % (total * 1_000_000)} callback.count: #{timings.count}" } if Sqreen::Weave.logger.debug?
|
251
|
+
timings = request[:timed_hooks].map(&:to_s)
|
252
|
+
total = request[:timed_hooks].sum(&:duration)
|
253
|
+
Sqreen::Weave.logger.debug { "request hook.total: #{'%.03fus' % (total * 1_000_000)} hook.count: #{timings.count}" } if Sqreen::Weave.logger.debug?
|
254
|
+
end
|
217
255
|
|
218
256
|
skipped = request[:skipped_callbacks].map(&:name)
|
219
257
|
skipped_rule_name = skipped.first && skipped.first =~ /weave,rule=(.*)$/ && $1
|
220
|
-
|
258
|
+
metrics_engine.update('request_overtime', now, skipped_rule_name, 1) if skipped_rule_name
|
259
|
+
# Sqreen.observations_queue.push(['request_overtime', skipped_rule_name, 1, utc_now]) if skipped_rule_name
|
221
260
|
|
222
|
-
sqreen_request_duration =
|
223
|
-
|
261
|
+
sqreen_request_duration = sqreen_timer.duration
|
262
|
+
metrics_engine.update('sq', now, nil, sqreen_request_duration * 1000)
|
263
|
+
# Sqreen.observations_queue.push(['sq', nil, sqreen_request_duration * 1000, utc_now])
|
224
264
|
|
225
|
-
request_duration =
|
226
|
-
|
265
|
+
request_duration = request_timer.duration
|
266
|
+
metrics_engine.update('req', now, nil, request_duration * 1000)
|
267
|
+
# Sqreen.observations_queue.push(['req', nil, request_duration * 1000, utc_now])
|
227
268
|
|
228
269
|
sqreen_request_ratio = (sqreen_request_duration * 100.0) / (request_duration - sqreen_request_duration)
|
229
|
-
|
270
|
+
metrics_engine.update('pct', now, nil, sqreen_request_ratio)
|
271
|
+
# Sqreen.observations_queue.push(['pct', nil, sqreen_request_ratio, utc_now])
|
272
|
+
Sqreen::Weave.logger.debug { "request sqreen_timer.ratio: #{'%.03f' % (sqreen_request_ratio / 100.0)}" } if Sqreen::Weave.logger.debug?
|
273
|
+
|
274
|
+
if request[:timed_level] >= 2
|
275
|
+
tallies = Hash.new(0.0)
|
276
|
+
request[:timed_callbacks].each do |timer|
|
277
|
+
duration = timer.duration
|
278
|
+
|
279
|
+
timer.tag =~ /weave,rule=(.*)$/ && rule = $1
|
280
|
+
next unless rule
|
281
|
+
|
282
|
+
whence = case timer.tag
|
283
|
+
when /@before/ then 'pre'
|
284
|
+
when /@after/ then 'post'
|
285
|
+
when /@raised/ then 'failing'
|
286
|
+
end
|
287
|
+
next unless whence
|
288
|
+
|
289
|
+
metric_name = "req.sq.#{rule}.#{whence}"
|
290
|
+
tallies[metric_name] += duration
|
291
|
+
end
|
292
|
+
tallies.each do |metric_name, duration|
|
293
|
+
metrics_engine.update(metric_name, now, nil, duration * 1000)
|
294
|
+
# Sqreen.observations_queue.push([metric_name, nil, duration * 1000, utc_now])
|
295
|
+
end
|
296
|
+
|
297
|
+
duration = request[:timed_hooks].sum(&:duration)
|
298
|
+
metrics_engine.update('req.sq.hook.overhead', now, nil, duration * 1000)
|
299
|
+
# Sqreen.observations_queue.push(['req.sq.hook.overhead', nil, duration * 1000, utc_now])
|
300
|
+
end
|
301
|
+
|
302
|
+
# shrinkwrap_timer.stop
|
303
|
+
|
304
|
+
# duration = shrinkwrap_timer.duration
|
305
|
+
# metrics_engine.update('sq.shrinkwrap', now, nil, duration * 1000)
|
230
306
|
end
|
231
307
|
end.install
|
232
308
|
|
233
309
|
### globally declare instrumentation ready
|
234
310
|
Sqreen.instrumentation_ready = true
|
311
|
+
Sqreen::Weave.logger.info { "Instrumentation activated" }
|
235
312
|
end
|
236
313
|
|
237
314
|
# needed by Sqreen::Runner
|
238
315
|
def remove_all_callbacks
|
239
316
|
Sqreen.instrumentation_ready = false
|
317
|
+
Sqreen::Weave.logger.info { "Instrumentation deactivated" }
|
240
318
|
|
241
319
|
loop do
|
242
320
|
hook = @hooks.pop
|
@@ -253,6 +331,15 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
253
331
|
klass = callback.klass
|
254
332
|
method = callback.method
|
255
333
|
|
334
|
+
if (call_count = ENV['SQREEN_DEBUG_CALL_COUNT'])
|
335
|
+
call_count = JSON.parse(call_count)
|
336
|
+
if callback.respond_to?(:rule_name) && call_count.key?(callback.rule_name)
|
337
|
+
count = call_count[callback.rule_name]
|
338
|
+
Sqreen::Weave.logger.debug { "override rule: #{callback.rule_name} call_count: #{count.inspect}" }
|
339
|
+
callback.instance_eval { @call_count_interval = call_count[callback.rule_name] }
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
256
343
|
if Sqreen::Graft::HookPoint.new("#{klass}.#{method}").exist?
|
257
344
|
hook_point = "#{klass}.#{method}"
|
258
345
|
elsif Sqreen::Graft::HookPoint.new("#{klass}##{method}").exist?
|
@@ -275,7 +362,6 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
275
362
|
a = call.args
|
276
363
|
r = call.remaining
|
277
364
|
|
278
|
-
Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#pre instance=#{i}" }
|
279
365
|
begin
|
280
366
|
ret = callback.pre(i, a, r)
|
281
367
|
rescue StandardError => e
|
@@ -286,17 +372,26 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
286
372
|
Sqreen::RemoteException.record(e)
|
287
373
|
end
|
288
374
|
end
|
289
|
-
Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#pre instance=#{i} => return=#{ret.inspect}" }
|
290
375
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
376
|
+
next if ret.nil? || !ret.is_a?(Hash)
|
377
|
+
|
378
|
+
throw_val =
|
379
|
+
case ret[:status]
|
380
|
+
when :skip, 'skip'
|
381
|
+
b.return(ret[:new_return_value]).break! if ret.key?(:new_return_value)
|
382
|
+
when :modify_args, 'modify_args'
|
383
|
+
b.args(ret[:args])
|
384
|
+
when :raise, 'raise'
|
385
|
+
if ret.key?(:exception)
|
386
|
+
b.raise(ret[:exception])
|
387
|
+
else
|
388
|
+
b.raise(Sqreen::AttackBlocked.new("Sqreen blocked a security threat (type: #{callback.rule_name}). No action is required."))
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
next unless throw_val
|
393
|
+
throw_val.break! if ret[:skip_rem_cbs]
|
394
|
+
throw(b, throw_val)
|
300
395
|
end
|
301
396
|
end
|
302
397
|
|
@@ -309,7 +404,6 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
309
404
|
a = call.args
|
310
405
|
r = call.remaining
|
311
406
|
|
312
|
-
Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#post instance=#{i}" }
|
313
407
|
begin
|
314
408
|
ret = callback.post(v, i, a, r)
|
315
409
|
rescue StandardError => e
|
@@ -320,7 +414,6 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
320
414
|
Sqreen::RemoteException.record(e)
|
321
415
|
end
|
322
416
|
end
|
323
|
-
Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#post instance=#{i} => return=#{ret.inspect}" }
|
324
417
|
|
325
418
|
case ret[:status]
|
326
419
|
when :override, 'override'
|
@@ -341,7 +434,6 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
341
434
|
a = call.args
|
342
435
|
r = call.remaining
|
343
436
|
|
344
|
-
Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#failing instance=#{i}" }
|
345
437
|
begin
|
346
438
|
ret = callback.failing(e, i, a, r)
|
347
439
|
rescue StandardError => e
|
@@ -352,7 +444,6 @@ class Sqreen::Weave::Legacy::Instrumentation
|
|
352
444
|
Sqreen::RemoteException.record(e)
|
353
445
|
end
|
354
446
|
end
|
355
|
-
Sqreen::Weave.logger.debug { "#{rule} klass=#{callback.klass} method=#{callback.method} when=#failing instance=#{i} => return=#{ret.inspect}" }
|
356
447
|
|
357
448
|
throw(b, b.raise(e)) if ret.nil? || !ret.is_a?(Hash)
|
358
449
|
|