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