contrast-agent 6.4.0 → 6.5.0
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 +4 -4
- data/ext/cs__contrast_patch/cs__contrast_patch.c +14 -1
- data/lib/contrast/agent/assess/finalizers/hash.rb +1 -0
- data/lib/contrast/agent/assess/policy/propagation_method.rb +5 -1
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +4 -0
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -0
- data/lib/contrast/agent/assess/policy/propagator/split.rb +3 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +5 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +8 -2
- data/lib/contrast/agent/assess/tracker.rb +12 -0
- data/lib/contrast/agent/inventory/dependency_analysis.rb +2 -2
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +1 -1
- data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
- data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
- data/lib/contrast/agent/patching/policy/method_policy.rb +3 -3
- data/lib/contrast/agent/reporting/reporter_heartbeat.rb +1 -3
- data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +17 -21
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +26 -3
- data/lib/contrast/agent/request_context.rb +8 -0
- data/lib/contrast/agent/service_heartbeat.rb +2 -3
- data/lib/contrast/agent/static_analysis.rb +1 -1
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/agent/worker_thread.rb +10 -0
- data/lib/contrast/components/agent.rb +51 -13
- data/lib/contrast/components/assess.rb +16 -0
- data/lib/contrast/components/contrast_service.rb +1 -1
- data/lib/contrast/components/heap_dump.rb +51 -1
- data/lib/contrast/components/inventory.rb +19 -13
- data/lib/contrast/components/logger.rb +18 -0
- data/lib/contrast/config/assess_configuration.rb +28 -0
- data/lib/contrast/config/base_configuration.rb +8 -2
- data/lib/contrast/config/root_configuration.rb +11 -8
- data/lib/contrast/config/service_configuration.rb +4 -4
- data/lib/contrast/config.rb +0 -6
- data/lib/contrast/extension/object.rb +19 -0
- data/lib/contrast/framework/rails/support.rb +4 -1
- data/lib/contrast/logger/log.rb +2 -1
- data/lib/contrast/utils/assess/event_limit_utils.rb +96 -0
- data/lib/contrast/utils/assess/propagation_method_utils.rb +27 -7
- data/lib/contrast/utils/log_utils.rb +2 -2
- data/lib/contrast/utils/patching/policy/patch_utils.rb +1 -1
- data/lib/contrast.rb +4 -19
- data/resources/assess/policy.json +4 -12
- data/ruby-agent.gemspec +2 -0
- metadata +43 -17
- data/lib/contrast/config/agent_configuration.rb +0 -63
- data/lib/contrast/config/heap_dump_configuration.rb +0 -59
- data/lib/contrast/config/inventory_configuration.rb +0 -33
- data/lib/contrast/config/logger_configuration.rb +0 -26
@@ -3,6 +3,8 @@
|
|
3
3
|
|
4
4
|
require 'rubygems/version'
|
5
5
|
require 'contrast/agent/rule_set'
|
6
|
+
require 'contrast/components/logger'
|
7
|
+
require 'contrast/components/heap_dump'
|
6
8
|
|
7
9
|
module Contrast
|
8
10
|
module Components
|
@@ -13,9 +15,50 @@ module Contrast
|
|
13
15
|
class Interface
|
14
16
|
include Contrast::Components::ComponentBase
|
15
17
|
|
18
|
+
def initialize hsh = {}
|
19
|
+
return unless hsh
|
20
|
+
|
21
|
+
@_enable = hsh[:enable]
|
22
|
+
@_start_bundled_service = hsh[:start_bundled_service]
|
23
|
+
@_omit_body = hsh[:omit_body]
|
24
|
+
@_service = Contrast::Config::ServiceConfiguration.new(hsh[:service])
|
25
|
+
@_logger = Contrast::Components::Logger::Interface.new(hsh[:logger])
|
26
|
+
@_ruby = Contrast::Config::RubyConfiguration.new(hsh[:ruby])
|
27
|
+
@_heap_dump = Contrast::Components::HeapDump::Interface.new(hsh[:heap_dump])
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Boolean, true]
|
31
|
+
def start_bundled_service?
|
32
|
+
@_start_bundled_service.nil? ? true : @_start_bundled_service
|
33
|
+
end
|
34
|
+
|
35
|
+
def service
|
36
|
+
return @_service unless @_service.nil?
|
37
|
+
|
38
|
+
@_service = Contrast::Config::ServiceConfiguration.new
|
39
|
+
end
|
40
|
+
|
41
|
+
def logger
|
42
|
+
return @_logger unless @_logger.nil?
|
43
|
+
|
44
|
+
@_logger = Contrast::Components::Logger::Interface.new
|
45
|
+
end
|
46
|
+
|
47
|
+
def ruby
|
48
|
+
return @_ruby unless @_ruby.nil?
|
49
|
+
|
50
|
+
@_ruby = Contrast::Config::RubyConfiguration.new
|
51
|
+
end
|
52
|
+
|
53
|
+
def heap_dump
|
54
|
+
return @_heap_dump unless @_heap_dump.nil?
|
55
|
+
|
56
|
+
@_heap_dump = Contrast::Components::HeapDump::Interface.new
|
57
|
+
end
|
58
|
+
|
16
59
|
def enabled?
|
17
|
-
@
|
18
|
-
@
|
60
|
+
@_enable = !false?(::Contrast::CONFIG.root.enable) if @_enable.nil?
|
61
|
+
@_enable
|
19
62
|
end
|
20
63
|
|
21
64
|
def disabled?
|
@@ -23,11 +66,11 @@ module Contrast
|
|
23
66
|
end
|
24
67
|
|
25
68
|
def enable!
|
26
|
-
@
|
69
|
+
@_enable = true
|
27
70
|
end
|
28
71
|
|
29
72
|
def disable!
|
30
|
-
@
|
73
|
+
@_enable = false
|
31
74
|
Contrast::Agent::TracePointHook.disable
|
32
75
|
Contrast::Agent.thread_watcher&.shutdown!
|
33
76
|
end
|
@@ -41,8 +84,7 @@ module Contrast
|
|
41
84
|
end
|
42
85
|
|
43
86
|
def patch_yield?
|
44
|
-
|
45
|
-
@_patch_yield
|
87
|
+
!false?(ruby.propagate_yield)
|
46
88
|
end
|
47
89
|
|
48
90
|
def interpolation_enabled?
|
@@ -52,18 +94,14 @@ module Contrast
|
|
52
94
|
end
|
53
95
|
|
54
96
|
def omit_body?
|
55
|
-
@_omit_body = true?(::Contrast::CONFIG.root.agent.omit_body) if @_omit_body.nil?
|
56
97
|
@_omit_body
|
57
98
|
end
|
58
99
|
|
59
100
|
def exception_control
|
60
101
|
@_exception_control ||= {
|
61
|
-
enable: true?(
|
62
|
-
status:
|
63
|
-
|
64
|
-
message:
|
65
|
-
::Contrast::CONFIG.root.agent.ruby.exceptions.override_message ||
|
66
|
-
Contrast::Utils::ObjectShare::OVERRIDE_MESSAGE
|
102
|
+
enable: true?(ruby.exceptions.capture),
|
103
|
+
status: ruby.exceptions.override_status || 403,
|
104
|
+
message: ruby.exceptions.override_message || Contrast::Utils::ObjectShare::OVERRIDE_MESSAGE
|
67
105
|
}
|
68
106
|
end
|
69
107
|
|
@@ -118,6 +118,22 @@ module Contrast
|
|
118
118
|
::Contrast::SETTINGS.assess_state.session_id
|
119
119
|
end
|
120
120
|
|
121
|
+
def max_source_events
|
122
|
+
::Contrast::CONFIG.root.assess.max_context_source_events
|
123
|
+
end
|
124
|
+
|
125
|
+
def max_propagation_events
|
126
|
+
::Contrast::CONFIG.root.assess.max_propagation_events
|
127
|
+
end
|
128
|
+
|
129
|
+
def time_limit_threshold
|
130
|
+
::Contrast::CONFIG.root.assess.time_limit_threshold
|
131
|
+
end
|
132
|
+
|
133
|
+
def max_rule_reported
|
134
|
+
::Contrast::CONFIG.root.assess.max_rule_reported
|
135
|
+
end
|
136
|
+
|
121
137
|
private
|
122
138
|
|
123
139
|
def forcibly_enabled?
|
@@ -29,7 +29,7 @@ module Contrast
|
|
29
29
|
|
30
30
|
# Requirement says "must be true" but that
|
31
31
|
# should be "must not be false" -- oops.
|
32
|
-
@_use_bundled_service ||= !false?(::Contrast::CONFIG.root.agent.start_bundled_service) &&
|
32
|
+
@_use_bundled_service ||= !false?(::Contrast::CONFIG.root.agent.start_bundled_service?) &&
|
33
33
|
# Either a valid host or a valid socket
|
34
34
|
# Path validity is the service's problem
|
35
35
|
(LOCALHOST.match?(host) || !!socket_path)
|
@@ -2,11 +2,61 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'contrast/components/base'
|
5
|
-
require 'contrast/
|
5
|
+
require 'contrast/config/base_configuration'
|
6
6
|
|
7
7
|
module Contrast
|
8
8
|
module Components
|
9
9
|
module HeapDump
|
10
|
+
# Interface used to build the HeapDump settings and component.
|
11
|
+
class Interface
|
12
|
+
include Contrast::Config::BaseConfiguration
|
13
|
+
|
14
|
+
DEFAULT_PATH = 'contrast_heap_dumps' # saved
|
15
|
+
DEFAULT_MS = 10_000
|
16
|
+
DEFAULT_COUNT = 5
|
17
|
+
|
18
|
+
def initialize hsh = {}
|
19
|
+
return unless hsh
|
20
|
+
|
21
|
+
@_enable = hsh[:enable]
|
22
|
+
@_path = hsh[:path]
|
23
|
+
@_delay_ms = hsh[:delay_ms]
|
24
|
+
@_window_ms = hsh[:window_ms]
|
25
|
+
@_count = hsh[:count]
|
26
|
+
@_clean = hsh[:clean]
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [Boolean, String] should dumps be taken
|
30
|
+
def enable
|
31
|
+
@_enable.nil? ? Contrast::Utils::ObjectShare::FALSE : @_enable
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [String, DEFAULT_PATH] dir to which dumps should be
|
35
|
+
def path
|
36
|
+
@_path ||= DEFAULT_PATH
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [Integer, DEFAULT_MS] time, in ms, after initialization
|
40
|
+
def delay_ms
|
41
|
+
@_delay_ms ||= DEFAULT_MS
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Integer, DEFAULT_MS] ms between each dump
|
45
|
+
def window_ms
|
46
|
+
@_window_ms ||= DEFAULT_MS
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [Integer, DEFAULT_COUNT] number of dumps to take
|
50
|
+
def count
|
51
|
+
@_count ||= DEFAULT_COUNT
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [Boolean, String] remove temporary objects or not
|
55
|
+
def clean
|
56
|
+
@_clean.nil? ? Contrast::Utils::ObjectShare::FALSE : @_clean
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
10
60
|
# A wrapper build around the Common Agent Configuration project to allow
|
11
61
|
# for access of the values contained in its
|
12
62
|
# parent_configuration_spec.yaml.
|
@@ -1,29 +1,35 @@
|
|
1
1
|
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'contrast/components/base'
|
5
|
+
|
4
6
|
module Contrast
|
5
7
|
module Components
|
6
8
|
module Inventory
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# parent_configuration_spec.yaml.
|
10
|
-
# Specifically, this allows for querying the state of the Inventory
|
11
|
-
# product.
|
9
|
+
# Interface component for Inventory settings used to store the values from
|
10
|
+
# settings file and assert state with check methods.
|
12
11
|
class Interface
|
13
12
|
include Contrast::Components::ComponentBase
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
# @return [Array, nil] tags
|
15
|
+
attr_accessor :tags
|
16
|
+
|
17
|
+
def initialize hsh = {}
|
18
|
+
return unless hsh
|
19
|
+
|
20
|
+
@enable = !false?(hsh[:enable])
|
21
|
+
@analyze_libraries = !false?(hsh[:analyze_libraries])
|
22
|
+
@tags = hsh[:tags]
|
18
23
|
end
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
@
|
25
|
+
# return [Boolean]
|
26
|
+
def enable
|
27
|
+
@enable.nil? ? true : @enable
|
23
28
|
end
|
24
29
|
|
25
|
-
|
26
|
-
|
30
|
+
# return [Boolean]
|
31
|
+
def analyze_libraries
|
32
|
+
@analyze_libraries.nil? ? true : @analyze_libraries
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
@@ -28,8 +28,26 @@ module Contrast
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
+
# So This class here follows the update for the configuration
|
32
|
+
# and from know on ( if it's as we planned it to be) it will hold the
|
33
|
+
# instance methods and will initialize new instances for where they're needed
|
31
34
|
class Interface
|
32
35
|
include InstanceMethods
|
36
|
+
|
37
|
+
# @return [String, nil]
|
38
|
+
attr_accessor :path
|
39
|
+
# @return [String, nil]
|
40
|
+
attr_accessor :level
|
41
|
+
# @return [String, nil]
|
42
|
+
attr_accessor :progname
|
43
|
+
|
44
|
+
def initialize hsh = {}
|
45
|
+
return unless hsh
|
46
|
+
|
47
|
+
@path = hsh[:path]
|
48
|
+
@level = hsh[:level]
|
49
|
+
@progname = hsh[:progname]
|
50
|
+
end
|
33
51
|
end
|
34
52
|
end
|
35
53
|
end
|
@@ -15,6 +15,10 @@ module Contrast
|
|
15
15
|
attr_writer :enable_scan_response, :enable_dynamic_sources, :sampling, :rules, :stacktraces
|
16
16
|
|
17
17
|
DEFAULT_STACKTRACES = 'ALL'
|
18
|
+
DEFAULT_MAX_SOURCE_EVENTS = 50_000
|
19
|
+
DEFAULT_MAX_PROPAGATION_EVENTS = 50_000
|
20
|
+
DEFAULT_MAX_RULE_REPORTED = 50_000
|
21
|
+
DEFAULT_MAX_RULE_TIME_THRESHOLD = 300_000
|
18
22
|
|
19
23
|
def initialize hsh = {}
|
20
24
|
return unless hsh
|
@@ -27,6 +31,10 @@ module Contrast
|
|
27
31
|
@sampling = Contrast::Config::SamplingConfiguration.new(hsh[:sampling])
|
28
32
|
@rules = Contrast::Config::AssessRulesConfiguration.new(hsh[:rules])
|
29
33
|
@stacktraces = hsh[:stacktraces]
|
34
|
+
@max_context_source_events = hsh[:max_context_source_events]
|
35
|
+
@max_propagation_events = hsh[:max_propagation_events]
|
36
|
+
@max_rule_reported = hsh[:max_rule_reported]
|
37
|
+
@time_limit_threshold = hsh[:time_limit_threshold]
|
30
38
|
end
|
31
39
|
|
32
40
|
# @return [Boolean, true]
|
@@ -58,6 +66,26 @@ module Contrast
|
|
58
66
|
def stacktraces
|
59
67
|
@stacktraces ||= DEFAULT_STACKTRACES
|
60
68
|
end
|
69
|
+
|
70
|
+
# @return [int] max number of context source events in single request
|
71
|
+
def max_context_source_events
|
72
|
+
@max_context_source_events ||= DEFAULT_MAX_SOURCE_EVENTS
|
73
|
+
end
|
74
|
+
|
75
|
+
# @return [int] max number of propagation events in single request
|
76
|
+
def max_propagation_events
|
77
|
+
@max_propagation_events ||= DEFAULT_MAX_PROPAGATION_EVENTS
|
78
|
+
end
|
79
|
+
|
80
|
+
# @return [int] max number of rules reported within time_limit_threshold
|
81
|
+
def max_rule_reported
|
82
|
+
@max_rule_reported ||= DEFAULT_MAX_RULE_REPORTED
|
83
|
+
end
|
84
|
+
|
85
|
+
# @return [int] max ms threshold for reporting rules
|
86
|
+
def time_limit_threshold
|
87
|
+
@time_limit_threshold ||= DEFAULT_MAX_RULE_TIME_THRESHOLD
|
88
|
+
end
|
61
89
|
end
|
62
90
|
end
|
63
91
|
end
|
@@ -10,12 +10,18 @@ module Contrast
|
|
10
10
|
# Configuration settings to usable Ruby classes.
|
11
11
|
module BaseConfiguration
|
12
12
|
extend Forwardable
|
13
|
+
AT_UNDERSCORE = '@_'
|
13
14
|
|
14
15
|
def to_hash
|
15
16
|
hsh = {}
|
16
17
|
instance_variables.each do |iv|
|
17
|
-
# strip the '@' to get the key
|
18
|
-
|
18
|
+
# strip the '@' of '@_' to get the key
|
19
|
+
string_iv = iv.to_s
|
20
|
+
key = if string_iv.include?(AT_UNDERSCORE)
|
21
|
+
string_iv[2..]
|
22
|
+
else
|
23
|
+
string_iv[1..]
|
24
|
+
end
|
19
25
|
hsh[key] = send(key.to_sym)
|
20
26
|
end
|
21
27
|
hsh
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'contrast/components/agent'
|
5
|
+
require 'contrast/components/inventory'
|
6
|
+
|
4
7
|
module Contrast
|
5
8
|
module Config
|
6
9
|
# The base of the Common Configuration settings.
|
@@ -9,7 +12,7 @@ module Contrast
|
|
9
12
|
|
10
13
|
# @return [Contrast::Config::ApiConfiguration]
|
11
14
|
attr_writer :api
|
12
|
-
# @return [Contrast::
|
15
|
+
# @return [Contrast::Components::Agent::Interface]
|
13
16
|
attr_writer :agent
|
14
17
|
# @return [Contrast::Config::ApplicationConfiguration]
|
15
18
|
attr_writer :application
|
@@ -17,7 +20,7 @@ module Contrast
|
|
17
20
|
attr_writer :server
|
18
21
|
# @return [Contrast::Config::AssessConfiguration]
|
19
22
|
attr_writer :assess
|
20
|
-
# @return [Contrast::
|
23
|
+
# @return [Contrast::Components::Inventory::Interface]
|
21
24
|
attr_writer :inventory
|
22
25
|
# @return [Contrast::Config::ProtectConfiguration]
|
23
26
|
attr_writer :protect
|
@@ -32,11 +35,11 @@ module Contrast
|
|
32
35
|
|
33
36
|
@api = Contrast::Config::ApiConfiguration.new(hsh[:api])
|
34
37
|
@enable = hsh[:enable]
|
35
|
-
@agent = Contrast::
|
38
|
+
@agent = Contrast::Components::Agent::Interface.new(hsh[:agent])
|
36
39
|
@application = Contrast::Config::ApplicationConfiguration.new(hsh[:application])
|
37
40
|
@server = Contrast::Config::ServerConfiguration.new(hsh[:server])
|
38
41
|
@assess = Contrast::Config::AssessConfiguration.new(hsh[:assess])
|
39
|
-
@inventory = Contrast::
|
42
|
+
@inventory = Contrast::Components::Inventory::Interface.new(hsh[:inventory])
|
40
43
|
@protect = Contrast::Config::ProtectConfiguration.new(hsh[:protect])
|
41
44
|
@service = Contrast::Config::ServiceConfiguration.new(hsh[:service])
|
42
45
|
end
|
@@ -46,9 +49,9 @@ module Contrast
|
|
46
49
|
@api ||= Contrast::Config::ApiConfiguration.new
|
47
50
|
end
|
48
51
|
|
49
|
-
# @return [Contrast::
|
52
|
+
# @return [Contrast::Components::Agent::Interface]
|
50
53
|
def agent
|
51
|
-
@agent ||= Contrast::
|
54
|
+
@agent ||= Contrast::Components::Agent::Interface.new
|
52
55
|
end
|
53
56
|
|
54
57
|
# @return [Contrast::Config::ApplicationConfiguration]
|
@@ -66,9 +69,9 @@ module Contrast
|
|
66
69
|
@assess ||= Contrast::Config::AssessConfiguration.new
|
67
70
|
end
|
68
71
|
|
69
|
-
# @return [Contrast::
|
72
|
+
# @return [Contrast::Components::Inventory::Interface]
|
70
73
|
def inventory
|
71
|
-
@inventory ||= Contrast::
|
74
|
+
@inventory ||= Contrast::Components::Inventory::Interface.new
|
72
75
|
end
|
73
76
|
|
74
77
|
# @return [Contrast::Config::ProtectConfiguration]
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
require 'contrast/
|
4
|
+
require 'contrast/components/logger'
|
5
5
|
|
6
6
|
module Contrast
|
7
7
|
module Config
|
@@ -31,13 +31,13 @@ module Contrast
|
|
31
31
|
@host = hsh[:host]
|
32
32
|
@port = hsh[:port]
|
33
33
|
@socket = hsh[:socket]
|
34
|
-
@logger = Contrast::
|
34
|
+
@logger = Contrast::Components::Logger::Interface.new(hsh[:logger])
|
35
35
|
@bypass = hsh[:bypass]
|
36
36
|
end
|
37
37
|
|
38
|
-
# @return [Contrast::
|
38
|
+
# @return [Contrast::Components::Logger::Interface]
|
39
39
|
def logger
|
40
|
-
@logger ||= Contrast::
|
40
|
+
@logger ||= Contrast::Components::Logger::Interface.new
|
41
41
|
end
|
42
42
|
|
43
43
|
# @return [Boolean, false]
|
data/lib/contrast/config.rb
CHANGED
@@ -11,10 +11,6 @@ module Contrast
|
|
11
11
|
end
|
12
12
|
|
13
13
|
require 'contrast/config/base_configuration'
|
14
|
-
|
15
|
-
require 'contrast/config/logger_configuration'
|
16
|
-
|
17
|
-
require 'contrast/config/heap_dump_configuration'
|
18
14
|
require 'contrast/config/service_configuration'
|
19
15
|
require 'contrast/config/exception_configuration'
|
20
16
|
require 'contrast/config/assess_rules_configuration'
|
@@ -24,10 +20,8 @@ require 'contrast/config/sampling_configuration'
|
|
24
20
|
|
25
21
|
require 'contrast/config/ruby_configuration'
|
26
22
|
require 'contrast/config/api_configuration'
|
27
|
-
require 'contrast/config/agent_configuration'
|
28
23
|
require 'contrast/config/application_configuration'
|
29
24
|
require 'contrast/config/server_configuration'
|
30
25
|
require 'contrast/config/assess_configuration'
|
31
|
-
require 'contrast/config/inventory_configuration'
|
32
26
|
require 'contrast/config/protect_configuration'
|
33
27
|
require 'contrast/config/root_configuration'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Some developers override various methods on Object, which can often involve
|
5
|
+
# changing expected method parity/behavior which in turn prevents us from being
|
6
|
+
# able to reliably use affected methods.
|
7
|
+
# We alias these method so that we always have access to them.
|
8
|
+
#
|
9
|
+
# Because we use these methods in constructing classes (e.g., calling #freeze
|
10
|
+
# on constants within class definitions) we do this aliasing ASAP.
|
11
|
+
class Object
|
12
|
+
alias_method :cs__class, :class
|
13
|
+
alias_method :cs__freeze, :freeze
|
14
|
+
alias_method :cs__frozen?, :frozen?
|
15
|
+
alias_method :cs__is_a?, :is_a?
|
16
|
+
alias_method :cs__method, :method
|
17
|
+
alias_method :cs__respond_to?, :respond_to?
|
18
|
+
alias_method :cs__singleton_class, :singleton_class
|
19
|
+
end
|
@@ -135,8 +135,11 @@ module Contrast
|
|
135
135
|
# @return [bool] whether the router is an engine or not.
|
136
136
|
def engine_route? route
|
137
137
|
return false unless route&.app&.app
|
138
|
+
return false unless route.app.is_a?(::ActionDispatch::Routing::Mapper::Constraints) ||
|
139
|
+
route.app.is_a?(::ActionDispatch::Routing::RouteSet::Dispatcher)
|
138
140
|
|
139
|
-
route.app.is_a?(
|
141
|
+
clazz = route.app.app.is_a?(Class) ? route.app.app : route.app.app.cs__class
|
142
|
+
clazz < ::Rails::Engine
|
140
143
|
end
|
141
144
|
|
142
145
|
# Recursively get final route traversing engines as required. Because this can only be called once, we store
|
data/lib/contrast/logger/log.rb
CHANGED
@@ -134,7 +134,8 @@ module Contrast
|
|
134
134
|
|
135
135
|
enable_trace_timing if current_level_const == ::Ougai::Logging::TRACE
|
136
136
|
|
137
|
-
|
137
|
+
progname = Contrast::CONFIG.root.agent.logger.progname
|
138
|
+
@_logger = build(path: current_path, level_const: current_level_const, progname: progname)
|
138
139
|
# If we're logging to a new path, then let's start it w/ our helpful
|
139
140
|
# data gathering messages
|
140
141
|
log_update if path_change
|
@@ -0,0 +1,96 @@
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'contrast/components/logger'
|
5
|
+
|
6
|
+
module Contrast
|
7
|
+
module Utils
|
8
|
+
module Assess
|
9
|
+
# EventLimitUtils is used to check and validate the number of source, propagation, or trigger events collected
|
10
|
+
# during the reporting time frame
|
11
|
+
module EventLimitUtils
|
12
|
+
include Contrast::Components::Logger::InstanceMethods
|
13
|
+
# Checks to see if the event limit for the policy type has been met or exceeded
|
14
|
+
# @param method_policy [Contrast::Agent::Patching::Policy::MethodPolicy] method to check for event limit
|
15
|
+
def event_limit? method_policy
|
16
|
+
return false unless (context = Contrast::Agent::REQUEST_TRACKER.current)
|
17
|
+
|
18
|
+
if method_policy.source_node
|
19
|
+
max = (::Contrast::ASSESS.max_source_events ||
|
20
|
+
Contrast::Config::AssessConfiguration::DEFAULT_MAX_SOURCE_EVENTS)
|
21
|
+
return at_limit?(method_policy, context.source_event_count, max)
|
22
|
+
|
23
|
+
end
|
24
|
+
if method_policy.propagation_node
|
25
|
+
max = (::Contrast::ASSESS.max_propagation_events ||
|
26
|
+
Contrast::Config::AssessConfiguration::DEFAULT_MAX_PROPAGATION_EVENTS)
|
27
|
+
return at_limit?(method_policy, context.propagation_event_count, max)
|
28
|
+
end
|
29
|
+
|
30
|
+
false # policy does not have limit
|
31
|
+
end
|
32
|
+
|
33
|
+
def event_limit_for_rule? rule_id
|
34
|
+
if Contrast::Utils::Timer.now_ms > threshold_time_limit
|
35
|
+
@_rule_counts = nil
|
36
|
+
@_threshold_time_limit = nil
|
37
|
+
threshold_time_limit
|
38
|
+
end
|
39
|
+
rule_counts[rule_id] += 1
|
40
|
+
# TODO: RUBY-1680 remove default
|
41
|
+
rule_counts[rule_id] >=
|
42
|
+
(::Contrast::ASSESS.max_rule_reported || Contrast::Config::AssessConfiguration::DEFAULT_MAX_RULE_REPORTED)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Increments the event count for the type of event that is being tracked
|
46
|
+
#
|
47
|
+
# @param node [Contrast::Agent::Assess::Policy::PolicyNode] policy to increment
|
48
|
+
def increment_event_count node
|
49
|
+
return unless (context = Contrast::Agent::REQUEST_TRACKER.current)
|
50
|
+
|
51
|
+
context.source_event_count += 1 if node.cs__is_a?(Contrast::Agent::Assess::Policy::SourceNode)
|
52
|
+
context.propagation_event_count += 1 if node.cs__is_a?(Contrast::Agent::Assess::Policy::PropagationNode)
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# helper method to check limit and log when necessary
|
58
|
+
def at_limit? method_policy, current_count, event_max
|
59
|
+
if current_count == event_max
|
60
|
+
logger.warn('Event Limit Reached:',
|
61
|
+
{
|
62
|
+
count: current_count,
|
63
|
+
max: event_max,
|
64
|
+
policy: method_policy.method_name,
|
65
|
+
node: method_policy
|
66
|
+
})
|
67
|
+
# increment to be over count for logging purposes
|
68
|
+
increment_event_count(method_policy)
|
69
|
+
return true
|
70
|
+
elsif current_count > event_max
|
71
|
+
# increment to be over count for logging purposes
|
72
|
+
increment_event_count(method_policy)
|
73
|
+
logger.warn('Event Limit Exceeded:',
|
74
|
+
{
|
75
|
+
count: current_count,
|
76
|
+
policy: method_policy.method_name,
|
77
|
+
node: method_policy
|
78
|
+
})
|
79
|
+
return true
|
80
|
+
end
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
84
|
+
def rule_counts
|
85
|
+
@_rule_counts ||= Hash.new { |h, k| h[k] = 0 }
|
86
|
+
end
|
87
|
+
|
88
|
+
# the time threshold for which to track rule counts resets when now >= threshold_time_limit
|
89
|
+
# @return [Integer]
|
90
|
+
def threshold_time_limit
|
91
|
+
@_threshold_time_limit ||= Contrast::Utils::Timer.now_ms + (::Contrast::ASSESS.time_limit_threshold || 0)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -92,20 +92,24 @@ module Contrast
|
|
92
92
|
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
93
93
|
# the invocation of the patched method.
|
94
94
|
# @param target [Object] the thing to which to propagate
|
95
|
+
# @param propagation_data [Contrast::Agent::Assess::Events::EventData] this will hold the
|
96
|
+
# object [Object] the Object on which the method was invoked
|
97
|
+
# args [Array<Object>] the Arguments with which the method was invoked
|
95
98
|
# @return [Boolean]
|
96
|
-
def can_propagate? propagation_node, preshift, target
|
99
|
+
def can_propagate? propagation_node, preshift, target, propagation_data
|
97
100
|
return false unless appropriate_target?(propagation_node, target)
|
98
101
|
return true if Contrast::Utils::Assess::TrackingUtil.tracked?(target)
|
99
|
-
|
100
|
-
# return true since we don't have preshift while using the original object.
|
101
|
-
return true
|
102
|
-
end
|
103
|
-
return false unless preshift
|
102
|
+
return false unless appropriate_source?(propagation_node, propagation_data, preshift)
|
104
103
|
|
105
104
|
propagation_node.sources.each do |source|
|
106
105
|
case source
|
107
106
|
when Contrast::Utils::ObjectShare::OBJECT_KEY
|
108
|
-
|
107
|
+
source_object = if propagation_node.use_original_object?
|
108
|
+
propagation_data.object
|
109
|
+
else
|
110
|
+
preshift.object
|
111
|
+
end
|
112
|
+
return true if Contrast::Utils::Assess::TrackingUtil.tracked?(source_object)
|
109
113
|
else
|
110
114
|
# has to be P, there's no ret source type (yet? ever?)
|
111
115
|
return true if preshift.args && Contrast::Utils::Assess::TrackingUtil.tracked?(preshift.args[source])
|
@@ -129,6 +133,22 @@ module Contrast
|
|
129
133
|
|
130
134
|
Contrast::Agent::Assess::Tracker.trackable?(target)
|
131
135
|
end
|
136
|
+
|
137
|
+
# A source is appropriate if it is available for propagation
|
138
|
+
#
|
139
|
+
# @param propagation_node [Contrast::Agent::Assess::Policy::PropagationNode] the node that governs this
|
140
|
+
# propagation event.
|
141
|
+
# @param propagation_data [Contrast::Agent::Assess::Events::EventData] this will hold the
|
142
|
+
# object [Object] the Object on which the method was invoked
|
143
|
+
# args [Array<Object>] the Arguments with which the method was invoked
|
144
|
+
# @param preshift [Contrast::Agent::Assess::PreShift] The capture of the state of the code just prior to
|
145
|
+
# the invocation of the patched method.
|
146
|
+
# @return [Boolean]
|
147
|
+
def appropriate_source? propagation_node, propagation_data, preshift
|
148
|
+
return true if preshift
|
149
|
+
|
150
|
+
propagation_node.use_original_object? && propagation_data&.object
|
151
|
+
end
|
132
152
|
end
|
133
153
|
end
|
134
154
|
end
|