contrast-agent 6.1.0 → 6.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.simplecov +1 -1
- data/Rakefile +1 -1
- data/ext/build_funchook.rb +3 -3
- data/ext/cs__assess_basic_object/cs__assess_basic_object.c +5 -1
- data/ext/extconf_common.rb +1 -1
- data/lib/contrast/agent/assess/finalizers/hash.rb +2 -2
- data/lib/contrast/agent/assess/policy/policy.rb +9 -10
- data/lib/contrast/agent/assess/policy/policy_node.rb +9 -10
- data/lib/contrast/agent/assess/policy/propagation_method.rb +3 -3
- data/lib/contrast/agent/assess/policy/propagation_node.rb +2 -3
- data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/buffer.rb +2 -1
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/split.rb +2 -2
- data/lib/contrast/agent/assess/policy/propagator/trim.rb +1 -1
- data/lib/contrast/agent/assess/policy/source_node.rb +1 -1
- data/lib/contrast/agent/assess/policy/trigger_method.rb +7 -7
- data/lib/contrast/agent/assess/policy/trigger_node.rb +16 -16
- data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +1 -1
- data/lib/contrast/agent/assess/property/evented.rb +2 -2
- data/lib/contrast/agent/assess/property/tagged.rb +2 -2
- data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +6 -8
- data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +6 -7
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +5 -5
- data/lib/contrast/agent/assess/rule/response/base_rule.rb +2 -3
- data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +8 -9
- data/lib/contrast/agent/assess/rule/response/click_jacking_header_rule.rb +4 -4
- data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +6 -6
- data/lib/contrast/agent/assess/rule/response/csp_header_missing_rule.rb +4 -4
- data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +4 -4
- data/lib/contrast/agent/assess/rule/response/x_content_type_header_rule.rb +4 -4
- data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +3 -4
- data/lib/contrast/agent/assess/tag.rb +13 -14
- data/lib/contrast/agent/at_exit_hook.rb +12 -1
- data/lib/contrast/agent/middleware.rb +6 -3
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +3 -3
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +2 -2
- data/lib/contrast/agent/patching/policy/method_policy_extend.rb +4 -4
- data/lib/contrast/agent/patching/policy/patch.rb +9 -9
- data/lib/contrast/agent/patching/policy/patch_status.rb +10 -3
- data/lib/contrast/agent/patching/policy/policy.rb +13 -15
- data/lib/contrast/agent/patching/policy/policy_node.rb +19 -21
- data/lib/contrast/agent/patching/policy/trigger_node.rb +1 -1
- data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +125 -125
- data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +2 -2
- data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -1
- data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +1 -1
- data/lib/contrast/agent/protect/policy/rule_applicator.rb +4 -4
- data/lib/contrast/agent/protect/rule/base.rb +30 -18
- data/lib/contrast/agent/protect/rule/base_service.rb +31 -14
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +16 -9
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +3 -3
- data/lib/contrast/agent/protect/rule/default_scanner.rb +2 -1
- data/lib/contrast/agent/protect/rule/deserialization.rb +18 -7
- data/lib/contrast/agent/protect/rule/http_method_tampering/http_method_tampering_input_classification.rb +74 -74
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +71 -53
- data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +3 -3
- data/lib/contrast/agent/protect/rule/no_sqli.rb +15 -16
- data/lib/contrast/agent/protect/rule/path_traversal.rb +13 -3
- data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +2 -2
- data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +1 -1
- data/lib/contrast/agent/protect/rule/sqli.rb +16 -23
- data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +61 -61
- data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_matcher.rb +29 -29
- data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +32 -32
- data/lib/contrast/agent/protect/rule/xss.rb +17 -0
- data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +14 -13
- data/lib/contrast/agent/protect/rule/xxe.rb +25 -3
- data/lib/contrast/agent/reaction_processor.rb +1 -1
- data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +36 -36
- data/lib/contrast/agent/reporting/masker/masker.rb +10 -10
- data/lib/contrast/agent/reporting/masker/masker_utils.rb +2 -2
- data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +8 -10
- data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +53 -5
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +25 -19
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +129 -17
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +20 -21
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_stack.rb +22 -0
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +26 -12
- data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +5 -5
- data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +7 -5
- data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +4 -10
- data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -2
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +6 -6
- data/lib/contrast/agent/reporting/reporting_utilities/response.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +7 -7
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +15 -15
- data/lib/contrast/agent/reporting/settings/application_settings.rb +1 -1
- data/lib/contrast/agent/reporting/settings/assess.rb +5 -5
- data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +3 -3
- data/lib/contrast/agent/reporting/settings/exclusions.rb +3 -3
- data/lib/contrast/agent/reporting/settings/protect.rb +20 -5
- data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +5 -5
- data/lib/contrast/agent/reporting/settings/reaction.rb +3 -3
- data/lib/contrast/agent/reporting/settings/sensitive_data_masking.rb +2 -2
- data/lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb +2 -2
- data/lib/contrast/agent/reporting/settings/server_features.rb +2 -2
- data/lib/contrast/agent/request.rb +2 -2
- data/lib/contrast/agent/request_context.rb +23 -19
- data/lib/contrast/agent/request_context_extend.rb +10 -23
- data/lib/contrast/agent/request_handler.rb +1 -1
- data/lib/contrast/agent/rule_set.rb +2 -2
- data/lib/contrast/agent/scope.rb +1 -1
- data/lib/contrast/agent/telemetry/base.rb +9 -5
- data/lib/contrast/agent/telemetry/events/exceptions/obfuscate.rb +119 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -2
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +1 -1
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +1 -1
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +16 -18
- data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +2 -2
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/communication/messaging_queue.rb +1 -1
- data/lib/contrast/api/communication/service_lifecycle.rb +1 -1
- data/lib/contrast/api/communication/socket.rb +1 -1
- data/lib/contrast/api/communication/socket_client.rb +1 -1
- data/lib/contrast/api/communication/speedracer.rb +2 -2
- data/lib/contrast/api/decorators/agent_startup.rb +10 -9
- data/lib/contrast/api/decorators/application_settings.rb +1 -1
- data/lib/contrast/api/decorators/application_startup.rb +4 -4
- data/lib/contrast/api/decorators/response_type.rb +4 -17
- data/lib/contrast/components/agent.rb +1 -1
- data/lib/contrast/components/base.rb +1 -1
- data/lib/contrast/components/config.rb +6 -6
- data/lib/contrast/components/contrast_service.rb +4 -1
- data/lib/contrast/components/sampling.rb +1 -1
- data/lib/contrast/components/settings.rb +52 -28
- data/lib/contrast/config/assess_rules_configuration.rb +1 -1
- data/lib/contrast/config/protect_rules_configuration.rb +1 -1
- data/lib/contrast/config/root_configuration.rb +1 -1
- data/lib/contrast/configuration.rb +4 -4
- data/lib/contrast/extension/assess/array.rb +1 -1
- data/lib/contrast/extension/assess/erb.rb +1 -1
- data/lib/contrast/extension/assess/marshal.rb +1 -1
- data/lib/contrast/extension/assess/string.rb +1 -1
- data/lib/contrast/extension/extension.rb +2 -2
- data/lib/contrast/framework/base_support.rb +8 -8
- data/lib/contrast/framework/grape/support.rb +3 -3
- data/lib/contrast/framework/manager.rb +5 -5
- data/lib/contrast/framework/manager_extend.rb +1 -1
- data/lib/contrast/framework/rack/patch/session_cookie.rb +1 -1
- data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +14 -3
- data/lib/contrast/framework/rails/patch/assess_configuration.rb +3 -3
- data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +1 -1
- data/lib/contrast/framework/rails/patch/support.rb +1 -1
- data/lib/contrast/framework/rails/support.rb +2 -2
- data/lib/contrast/framework/sinatra/support.rb +1 -1
- data/lib/contrast/logger/aliased_logging.rb +29 -22
- data/lib/contrast/logger/cef_log.rb +14 -14
- data/lib/contrast/logger/format.rb +1 -1
- data/lib/contrast/logger/log.rb +8 -8
- data/lib/contrast/tasks/config.rb +12 -12
- data/lib/contrast/tasks/service.rb +2 -2
- data/lib/contrast/utils/assess/tracking_util.rb +4 -4
- data/lib/contrast/utils/class_util.rb +4 -4
- data/lib/contrast/utils/findings.rb +3 -3
- data/lib/contrast/utils/hash_digest.rb +6 -7
- data/lib/contrast/utils/head_dump_utils_extend.rb +1 -1
- data/lib/contrast/utils/invalid_configuration_util.rb +1 -1
- data/lib/contrast/utils/log_utils.rb +4 -4
- data/lib/contrast/utils/lru_cache.rb +1 -1
- data/lib/contrast/utils/metrics_hash.rb +1 -1
- data/lib/contrast/utils/middleware_utils.rb +5 -5
- data/lib/contrast/utils/net_http_base.rb +4 -4
- data/lib/contrast/utils/os.rb +1 -1
- data/lib/contrast/utils/patching/policy/patch_utils.rb +2 -2
- data/lib/contrast/utils/request_utils.rb +2 -2
- data/lib/contrast/utils/sha256_builder.rb +4 -4
- data/lib/contrast/utils/stack_trace_utils.rb +31 -13
- data/lib/contrast/utils/telemetry.rb +6 -9
- data/lib/contrast/utils/telemetry_client.rb +5 -5
- data/lib/contrast/utils/telemetry_hash.rb +1 -1
- data/lib/contrast/utils/telemetry_identifier.rb +2 -2
- data/lib/contrast/utils/timer.rb +1 -1
- data/resources/assess/policy.json +1 -1
- metadata +15 -13
@@ -94,7 +94,7 @@ module Contrast
|
|
94
94
|
rescue Psych::Exception => e
|
95
95
|
log_yaml_parse_error(path, e)
|
96
96
|
rescue RuntimeError => e
|
97
|
-
puts
|
97
|
+
puts("WARN: Unable to load configuration. #{ e }; path: #{ path }, pwd: #{ Dir.pwd }")
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
@@ -182,7 +182,7 @@ module Contrast
|
|
182
182
|
if logger
|
183
183
|
logger.warn('YAML validator found an error', hash)
|
184
184
|
else
|
185
|
-
puts
|
185
|
+
puts("CONTRAST - WARN: YAML validator found an error. #{ hash.inspect }")
|
186
186
|
end
|
187
187
|
end
|
188
188
|
|
@@ -190,7 +190,7 @@ module Contrast
|
|
190
190
|
if logger
|
191
191
|
logger.warn('Configuration file is not readable by current user', path: path)
|
192
192
|
else
|
193
|
-
puts
|
193
|
+
puts("CONTRAST - WARN: Configuration file is not readable by current user; path: #{ path }")
|
194
194
|
end
|
195
195
|
end
|
196
196
|
|
@@ -198,7 +198,7 @@ module Contrast
|
|
198
198
|
if logger
|
199
199
|
logger.warn('Deprecated property in use', old_method: old_method, new_method: new_method)
|
200
200
|
else
|
201
|
-
puts
|
201
|
+
puts("CONTRAST - WARN: Deprecated property in use; old_method: #{ old_method }, new_method: #{ new_method }")
|
202
202
|
end
|
203
203
|
end
|
204
204
|
|
@@ -53,7 +53,7 @@ module Contrast
|
|
53
53
|
return ret unless Contrast::Agent::Assess::Tracker.tracked?(ret)
|
54
54
|
|
55
55
|
properties.cleanup_tags
|
56
|
-
event_data = Contrast::Agent::Assess::Events::EventData.new
|
56
|
+
event_data = Contrast::Agent::Assess::Events::EventData.new(ARRAY_JOIN_NODE, ret, ary, ret, [separator])
|
57
57
|
properties.build_event(event_data)
|
58
58
|
properties.event.instance_variable_set(:@_parent_events, parent_events)
|
59
59
|
ret
|
@@ -20,7 +20,7 @@ module ERBPropagator
|
|
20
20
|
|
21
21
|
erb_pre_result = preshift.object.src
|
22
22
|
parent_events = []
|
23
|
-
binding_variable_set
|
23
|
+
binding_variable_set(binding_variable_set, used_binding, erb_pre_result, properties, parent_events, ret)
|
24
24
|
properties.build_event(Contrast::Agent::Assess::Events::EventData.new(patcher,
|
25
25
|
ret,
|
26
26
|
preshift.object,
|
@@ -43,7 +43,7 @@ module Contrast
|
|
43
43
|
properties.copy_from(source, ret)
|
44
44
|
|
45
45
|
node = Contrast::Agent::Assess::Policy::Policy.instance.find_propagator_node('Marshal', :load, false)
|
46
|
-
event_data = Contrast::Agent::Assess::Events::EventData.new
|
46
|
+
event_data = Contrast::Agent::Assess::Events::EventData.new(node, ret, self, ret, args)
|
47
47
|
properties.build_event(event_data)
|
48
48
|
rescue StandardError => e
|
49
49
|
logger.error('Unable to run Assess for Marshal.load', e)
|
@@ -43,7 +43,7 @@ module Contrast
|
|
43
43
|
offset = 0
|
44
44
|
inputs.each do |input|
|
45
45
|
properties.copy_from(input, result, offset)
|
46
|
-
add_dynamic_sources_info
|
46
|
+
add_dynamic_sources_info(input, result)
|
47
47
|
offset += input.length
|
48
48
|
parent_event = Contrast::Agent::Assess::Tracker.properties(input)&.event
|
49
49
|
parent_events << parent_event if parent_event
|
@@ -7,19 +7,19 @@ module Contrast
|
|
7
7
|
module BaseSupport
|
8
8
|
# The top level module name used by the framework
|
9
9
|
def detection_class
|
10
|
-
raise
|
10
|
+
raise(NoMethodError('Subclasses of BaseSupport should implement this method'))
|
11
11
|
end
|
12
12
|
|
13
13
|
def version
|
14
|
-
raise
|
14
|
+
raise(NoMethodError('Subclasses of BaseSupport should implement this method'))
|
15
15
|
end
|
16
16
|
|
17
17
|
def application_name
|
18
|
-
raise
|
18
|
+
raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
|
19
19
|
end
|
20
20
|
|
21
21
|
def server_type
|
22
|
-
raise
|
22
|
+
raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
|
23
23
|
end
|
24
24
|
|
25
25
|
# Find all the predefined routes for this application and append them to the
|
@@ -27,19 +27,19 @@ module Contrast
|
|
27
27
|
# msg should be a Contrast::Api::Dtm::ApplicationUpdate or some other msg
|
28
28
|
# that has a routes array consisting of Contrast::Api::Dtm::RouteCoverage
|
29
29
|
def collect_routes
|
30
|
-
raise
|
30
|
+
raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
|
31
31
|
end
|
32
32
|
|
33
33
|
def current_route_coverage
|
34
|
-
raise
|
34
|
+
raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
|
35
35
|
end
|
36
36
|
|
37
37
|
def current_route
|
38
|
-
raise
|
38
|
+
raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
|
39
39
|
end
|
40
40
|
|
41
41
|
def retrieve_request _env
|
42
|
-
raise
|
42
|
+
raise(NoMethodError, 'Subclasses of BaseSupport should implement this method')
|
43
43
|
end
|
44
44
|
|
45
45
|
# Some Frameworks require specific patching for their classes to handle
|
@@ -112,7 +112,7 @@ module Contrast
|
|
112
112
|
full_route ||= request.env[::Rack::PATH_INFO]
|
113
113
|
|
114
114
|
new_route_coverage = Contrast::Agent::Reporting::RouteCoverage.new
|
115
|
-
new_route_coverage.attach_rack_based_data
|
115
|
+
new_route_coverage.attach_rack_based_data(final_controller, method, route_pattern, full_route)
|
116
116
|
end
|
117
117
|
|
118
118
|
# Search object space for grape controllers--any class that subclasses ::Grape::API.
|
@@ -151,7 +151,7 @@ module Contrast
|
|
151
151
|
# Grape controller actually has endpoints and each endpoint
|
152
152
|
# has routes and that's why we need to do it that way
|
153
153
|
controller = controllers.pop
|
154
|
-
return _route_recurse
|
154
|
+
return _route_recurse(method, route, controllers) unless controller
|
155
155
|
|
156
156
|
contr_routes = controller.endpoints&.map(&:routes)&.flatten || []
|
157
157
|
route_pattern = contr_routes&.find do |r|
|
@@ -159,7 +159,7 @@ module Contrast
|
|
159
159
|
end
|
160
160
|
return controller, route_pattern unless route_pattern.nil?
|
161
161
|
|
162
|
-
_route_recurse
|
162
|
+
_route_recurse(method, route, controllers)
|
163
163
|
end
|
164
164
|
|
165
165
|
# Get route and do some cleaning
|
@@ -64,25 +64,25 @@ module Contrast
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def platform_version
|
67
|
-
framework_version = first_framework_result
|
67
|
+
framework_version = first_framework_result(:version, '')
|
68
68
|
|
69
69
|
Contrast::Framework::PlatformVersion.from_string(framework_version)
|
70
70
|
end
|
71
71
|
|
72
72
|
def platform_version_string
|
73
|
-
first_framework_result
|
73
|
+
first_framework_result(:version, '')
|
74
74
|
end
|
75
75
|
|
76
76
|
def server_type
|
77
|
-
first_framework_result
|
77
|
+
first_framework_result(:server_type, 'rack')
|
78
78
|
end
|
79
79
|
|
80
80
|
def app_name
|
81
|
-
first_framework_result
|
81
|
+
first_framework_result(:application_name, 'root')
|
82
82
|
end
|
83
83
|
|
84
84
|
def app_root
|
85
|
-
found = first_framework_result
|
85
|
+
found = first_framework_result(:application_root, nil)
|
86
86
|
found || ::Rack::Directory.new('').root
|
87
87
|
end
|
88
88
|
|
@@ -25,7 +25,7 @@ module Contrast
|
|
25
25
|
def instrument
|
26
26
|
@_instrument ||= begin
|
27
27
|
::Rack::Session::Cookie.class_eval do
|
28
|
-
alias_method
|
28
|
+
alias_method(:cs__patched_initialize, :initialize)
|
29
29
|
def initialize app, options = {} # rubocop:disable Style/OptionHash
|
30
30
|
Contrast::Framework::Rack::Patch::SessionCookie.analyze(options)
|
31
31
|
cs__patched_initialize(app, options)
|
@@ -16,8 +16,19 @@ module Contrast
|
|
16
16
|
def send_messages
|
17
17
|
return unless (context = Contrast::Agent::REQUEST_TRACKER.current)
|
18
18
|
|
19
|
-
|
20
|
-
|
19
|
+
if Contrast::Agent::Reporter.enabled?
|
20
|
+
[
|
21
|
+
context.new_observed_route,
|
22
|
+
Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.server_activity),
|
23
|
+
Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.activity.library_usages),
|
24
|
+
Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.activity)
|
25
|
+
].each do |event|
|
26
|
+
Contrast::Agent.reporter&.send_event_immediately(event)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
[context.server_activity, context.activity, context.observed_route].each do |msg|
|
30
|
+
Contrast::Agent.messaging_queue&.send_event_immediately(msg)
|
31
|
+
end
|
21
32
|
end
|
22
33
|
end
|
23
34
|
|
@@ -27,7 +38,7 @@ module Contrast
|
|
27
38
|
# normally pre->in->post filters are applied however, in a streamed response we can run into a case
|
28
39
|
# where it's pre -> in -> post -> more infilters in order to submit anything found during the
|
29
40
|
# infilters after the response has been written we need to explicitly send them
|
30
|
-
alias_method
|
41
|
+
alias_method(:cs__close, :close)
|
31
42
|
def close
|
32
43
|
Contrast::Framework::Rails::Patch::ActionControllerLiveBuffer.send_messages
|
33
44
|
cs__close
|
@@ -49,7 +49,7 @@ module Contrast
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def apply_session_timeout *args
|
52
|
-
return if ::Contrast::ASSESS.rule_disabled?
|
52
|
+
return if ::Contrast::ASSESS.rule_disabled?(CS__SESSION_TIMEOUT_NAME)
|
53
53
|
return unless vulnerable_setting?(:expire_after, SAFE_SESSION_TIMEOUT, args,
|
54
54
|
comparison_type: :greater_than, safe_default: false)
|
55
55
|
|
@@ -64,7 +64,7 @@ module Contrast
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def apply_secure_cookie_disabled *args
|
67
|
-
return if ::Contrast::ASSESS.rule_disabled?
|
67
|
+
return if ::Contrast::ASSESS.rule_disabled?(CS__SECURE_RULE_NAME)
|
68
68
|
return unless vulnerable_setting?(:secure, true, args)
|
69
69
|
|
70
70
|
rails_session_settings = args[1]
|
@@ -78,7 +78,7 @@ module Contrast
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def apply_httponly_disabled *args
|
81
|
-
return if ::Contrast::ASSESS.rule_disabled?
|
81
|
+
return if ::Contrast::ASSESS.rule_disabled?(CS__HTTPONLY_RULE_NAME)
|
82
82
|
return unless vulnerable_setting?(:httponly, true, args)
|
83
83
|
|
84
84
|
rails_session_settings = args[1]
|
@@ -14,7 +14,7 @@ module Contrast
|
|
14
14
|
def self.instrument
|
15
15
|
@_instrument ||= begin
|
16
16
|
::Rails::Application::Configuration.class_eval do
|
17
|
-
alias_method
|
17
|
+
alias_method(:cs__patched_session_store, :session_store)
|
18
18
|
def session_store *args, **kwargs
|
19
19
|
ret = cs__patched_session_store(*args, **kwargs)
|
20
20
|
Contrast::Framework::Rails::Patch::AssessConfiguration.analyze_session_store(*args, **kwargs)
|
@@ -20,7 +20,7 @@ module Contrast
|
|
20
20
|
# (i.e., where we normally patch) we will miss the configuration
|
21
21
|
# and will never be able to report session misconfiguration rules.
|
22
22
|
Contrast::Framework::Rails::Patch::RailsApplicationConfiguration.instrument
|
23
|
-
require
|
23
|
+
require('contrast/framework/rails/railtie') if ::Rails::VERSION::MAJOR.to_i >= 3
|
24
24
|
end
|
25
25
|
|
26
26
|
# (See BaseSupport#after_load_patches)
|
@@ -104,7 +104,7 @@ module Contrast
|
|
104
104
|
end
|
105
105
|
|
106
106
|
new_route_coverage = Contrast::Agent::Reporting::RouteCoverage.new
|
107
|
-
new_route_coverage.attach_rails_data
|
107
|
+
new_route_coverage.attach_rails_data(route, original_url)
|
108
108
|
rescue StandardError => e
|
109
109
|
logger.warn('Unable to determine the current route of this request', e)
|
110
110
|
nil
|
@@ -153,7 +153,7 @@ module Contrast
|
|
153
153
|
# If the current routing node points to a sub-app (::Rais::Engine), dive deeper.
|
154
154
|
# Have sub-app route the remainder of the url.
|
155
155
|
if engine_route?(route)
|
156
|
-
new_req = retrieve_request
|
156
|
+
new_req = retrieve_request(request.env)
|
157
157
|
new_req.path_info = new_req.path_info.gsub(match.to_s, '')
|
158
158
|
get_full_route(new_req, route.app.app.routes.router, path << match.to_s)
|
159
159
|
else
|
@@ -101,7 +101,7 @@ module Contrast
|
|
101
101
|
full_route ||= request.env[::Rack::PATH_INFO]
|
102
102
|
|
103
103
|
new_route_coverage = Contrast::Agent::Reporting::RouteCoverage.new
|
104
|
-
new_route_coverage.attach_rack_based_data
|
104
|
+
new_route_coverage.attach_rack_based_data(final_controller, method, route_pattern, full_route)
|
105
105
|
end
|
106
106
|
|
107
107
|
# Search object space for sinatra controllers--any class that subclasses ::Sinatra::Base.
|
@@ -2,6 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'contrast/agent/telemetry/events/exceptions/telemetry_exceptions'
|
5
|
+
require 'contrast/agent/telemetry/events/exceptions/obfuscate'
|
5
6
|
|
6
7
|
module Contrast
|
7
8
|
module Logger
|
@@ -40,23 +41,29 @@ module Contrast
|
|
40
41
|
|
41
42
|
private
|
42
43
|
|
43
|
-
def build_exclusion
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
44
|
+
def build_exclusion _type, _message = nil, _exception = nil, _data = nil
|
45
|
+
# TODO: RUBY-1698
|
46
|
+
nil
|
47
|
+
# start = caller_locations&.find_index { |stack| stack.to_s.include?(type) }
|
48
|
+
# stack_trace = start ? caller_locations(start + 1, 20) : caller_locations(20, 20)
|
49
|
+
# stack_frame_type = Contrast::Agent::Telemetry::TelemetryException::Obfuscate.obfuscate_type(
|
50
|
+
# stack_trace[1].path.delete_prefix(Dir.pwd))
|
51
|
+
# message_exception_type = Contrast::Agent::Telemetry::TelemetryException::Obfuscate.obfuscate_exception_type(
|
52
|
+
# exception ? exception.cs__class.to_s : stack_frame_type.split('/').last)
|
53
|
+
# stack_frame_function = stack_trace[1].label
|
54
|
+
# key = "#{ stack_frame_type }|#{ stack_frame_function }|#{ message }"
|
55
|
+
# if TELEMETRY_EXCEPTIONS[key]
|
56
|
+
# TELEMETRY_EXCEPTIONS.increment(key)
|
57
|
+
# return
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# event_message = create_message(stack_frame_function,
|
61
|
+
# stack_frame_type, message_exception_type,
|
62
|
+
# data, exception,
|
63
|
+
# message)
|
64
|
+
# TELEMETRY_EXCEPTIONS[key] = event_message
|
65
|
+
# rescue StandardError => e
|
66
|
+
# debug('Unable to report exception to telemetry', e)
|
60
67
|
end
|
61
68
|
|
62
69
|
def create_message stack_frame_function, stack_frame_type, message_exception_type, data, exception, message
|
@@ -65,10 +72,10 @@ module Contrast
|
|
65
72
|
else
|
66
73
|
message
|
67
74
|
end
|
68
|
-
module_name =
|
69
|
-
stack_frame = Contrast::Agent::Telemetry::TelemetryException::StackFrame.build
|
75
|
+
module_name = message_exception_type ? message_exception_type.split('::')[0] : nil
|
76
|
+
stack_frame = Contrast::Agent::Telemetry::TelemetryException::StackFrame.build(stack_frame_function,
|
70
77
|
stack_frame_type,
|
71
|
-
module_name
|
78
|
+
module_name)
|
72
79
|
message_exception = Contrast::Agent::Telemetry::TelemetryException::MessageException.build(
|
73
80
|
message_exception_type,
|
74
81
|
message_for_exception,
|
@@ -79,8 +86,8 @@ module Contrast
|
|
79
86
|
else
|
80
87
|
exception.cs__is_a?(Hash) ? exception : {}
|
81
88
|
end
|
82
|
-
message = Contrast::Agent::Telemetry::TelemetryException::Message.build
|
83
|
-
Contrast::Agent::Telemetry::TelemetryException::Event.new
|
89
|
+
message = Contrast::Agent::Telemetry::TelemetryException::Message.build(tags, [message_exception])
|
90
|
+
Contrast::Agent::Telemetry::TelemetryException::Event.new(message)
|
84
91
|
end
|
85
92
|
end
|
86
93
|
end
|
@@ -30,7 +30,7 @@ module Contrast
|
|
30
30
|
else
|
31
31
|
cs__error(*args, **kwargs)
|
32
32
|
end
|
33
|
-
args.each { |arg| raise
|
33
|
+
args.each { |arg| raise(arg) if arg && arg.cs__class < Exception }
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -69,11 +69,11 @@ module Contrast
|
|
69
69
|
if @_cef_logger
|
70
70
|
@_cef_logger.error('Unable to process update to LoggerManager.', e)
|
71
71
|
else
|
72
|
-
puts
|
73
|
-
raise
|
72
|
+
puts('Unable to process update to LoggerManager.')
|
73
|
+
raise(e) if ENV['CONTRAST__AGENT__RUBY_MORE_COWBELL']
|
74
74
|
|
75
|
-
puts
|
76
|
-
puts
|
75
|
+
puts(e.message)
|
76
|
+
puts(e.backtrace.join("\n"))
|
77
77
|
end
|
78
78
|
# rubocop:enable Rails/Output
|
79
79
|
end
|
@@ -99,28 +99,28 @@ module Contrast
|
|
99
99
|
|
100
100
|
def virtual_patch_message patch, outcome
|
101
101
|
message = "Virtual Patch #{ patch.fetch(:name, '') } - #{ patch[:uuid] } was triggered by this request."
|
102
|
-
log
|
102
|
+
log([message, patch, outcome], ::Logger::Severity::DEBUG)
|
103
103
|
end
|
104
104
|
|
105
105
|
def bot_blocking_message matching_bot, outcome
|
106
106
|
message = "User agent #{ matching_bot[:user_agent] } matched the disallowed value #{ matching_bot[:bot] }"
|
107
|
-
log
|
107
|
+
log([message, matching_bot, outcome], ::Logger::Severity::DEBUG)
|
108
108
|
end
|
109
109
|
|
110
110
|
def ip_denylisted_message remote_ip, block_entry, outcome
|
111
111
|
message = "IP Address #{ remote_ip } matched the disallowed value" \
|
112
112
|
"#{ block_entry[:ip] } in the IP Blacklist #{ block_entry[:uuid] }"
|
113
|
-
log
|
113
|
+
log([message, block_entry, outcome], ::Logger::Severity::DEBUG)
|
114
114
|
end
|
115
115
|
|
116
116
|
def successful_attack rule_id, outcome, input_type = nil, input_value = nil
|
117
117
|
if input_type.present? && input_value.present?
|
118
118
|
successful_attack_with_input = "#{ input_type } had a value that successfully exploited" \
|
119
119
|
"#{ rule_id } - #{ input_value }"
|
120
|
-
log
|
120
|
+
log([successful_attack_with_input, rule_id, outcome], ::Logger::Severity::WARN)
|
121
121
|
else
|
122
122
|
successful_attack_wo_input = "An effective attack was detected against #{ rule_id }"
|
123
|
-
log
|
123
|
+
log([successful_attack_wo_input, rule_id, outcome], ::Logger::Severity::WARN)
|
124
124
|
end
|
125
125
|
end
|
126
126
|
|
@@ -128,10 +128,10 @@ module Contrast
|
|
128
128
|
if input_type.present? && input_value.present?
|
129
129
|
ineffective_attack_with_input = "#{ input_type } had a value that matched a signature for, " \
|
130
130
|
"but did not successfully exploit #{ rule_id } - #{ input_value }"
|
131
|
-
log
|
131
|
+
log([ineffective_attack_with_input, rule_id, outcome], ::Logger::Severity::WARN)
|
132
132
|
else
|
133
133
|
ineffective_attack_wo_input = "An unsuccessful attack was detected against #{ rule_id }"
|
134
|
-
log
|
134
|
+
log([ineffective_attack_wo_input, rule_id, outcome], ::Logger::Severity::WARN)
|
135
135
|
end
|
136
136
|
end
|
137
137
|
|
@@ -140,10 +140,10 @@ module Contrast
|
|
140
140
|
if input_type.present? && input_value.present?
|
141
141
|
suspicious_attack_with = "#{ input_type } included a potential attack value that was detected" \
|
142
142
|
"as suspicious using #{ rule_id } - #{ input_value }"
|
143
|
-
log
|
143
|
+
log([suspicious_attack_with, rule_id, outcome], ::Logger::WARN)
|
144
144
|
elsif input_value.present?
|
145
145
|
suspicious_attack_without = "Suspicious activity indicates a potential attack using #{ rule_id }"
|
146
|
-
log
|
146
|
+
log([suspicious_attack_without, rule_id, outcome], ::Logger::WARN)
|
147
147
|
end
|
148
148
|
end
|
149
149
|
end
|
@@ -10,6 +10,7 @@ module Contrast
|
|
10
10
|
# Our format for the Ougai logger allowing for custom log format that
|
11
11
|
# extends the behavior of the default Ougai logger
|
12
12
|
class Format < Ougai::Formatters::Bunyan
|
13
|
+
NO_REQUEST_HASH = { request_id: -1 }.cs__freeze
|
13
14
|
LOG_TRACKER = Contrast::Utils::ThreadTracker.new
|
14
15
|
# Our override of the _call method to add in the extra data that we want,
|
15
16
|
# based on
|
@@ -49,7 +50,6 @@ module Contrast
|
|
49
50
|
hash
|
50
51
|
end
|
51
52
|
|
52
|
-
NO_REQUEST_HASH = { request_id: -1 }.cs__freeze
|
53
53
|
def request_hash
|
54
54
|
@request_tracker_defined ||= defined?(Contrast::Agent) && defined?(Contrast::Agent::REQUEST_TRACKER)
|
55
55
|
return NO_REQUEST_HASH unless @request_tracker_defined
|
data/lib/contrast/logger/log.rb
CHANGED
@@ -44,8 +44,8 @@ module Contrast
|
|
44
44
|
untimed_func_symbol = "untimed_#{ meth_spec.method_name }".to_sym
|
45
45
|
send_to = class_method ? meth_spec.clazz.cs__singleton_class : meth_spec.clazz
|
46
46
|
meth_spec.clazz.class_eval do
|
47
|
-
include
|
48
|
-
extend
|
47
|
+
include(Contrast::Components::Logger::InstanceMethods)
|
48
|
+
extend(Contrast::Components::Logger::InstanceMethods)
|
49
49
|
|
50
50
|
send_to.send(:alias_method, untimed_func_symbol, meth_spec.method_name)
|
51
51
|
meth_spec.aliased = true
|
@@ -73,7 +73,7 @@ module Contrast
|
|
73
73
|
next if meth_spec.aliased
|
74
74
|
|
75
75
|
is_class_method = meth_spec.clazz.singleton_methods(false).include?(meth_spec.method_name)
|
76
|
-
trace_time_class_method
|
76
|
+
trace_time_class_method(meth_spec, is_class_method)
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
@@ -96,7 +96,7 @@ module Contrast
|
|
96
96
|
else
|
97
97
|
cs__error(*args, **kwargs)
|
98
98
|
end
|
99
|
-
args.each { |arg| raise
|
99
|
+
args.each { |arg| raise(arg) if arg && arg.cs__class < Exception }
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
@@ -142,11 +142,11 @@ module Contrast
|
|
142
142
|
if logger
|
143
143
|
logger.error('Unable to process update to LoggerManager.', e)
|
144
144
|
else
|
145
|
-
puts
|
146
|
-
raise
|
145
|
+
puts('Unable to process update to LoggerManager.')
|
146
|
+
raise(e) if ENV['CONTRAST__AGENT__RUBY_MORE_COWBELL']
|
147
147
|
|
148
|
-
puts
|
149
|
-
puts
|
148
|
+
puts(e.message)
|
149
|
+
puts(e.backtrace.join("\n"))
|
150
150
|
end
|
151
151
|
end
|
152
152
|
|
@@ -75,7 +75,7 @@ module Contrast
|
|
75
75
|
missing = []
|
76
76
|
api_hash = config.root.api.to_hash
|
77
77
|
api_hash.each_key do |key|
|
78
|
-
value = mask_keys
|
78
|
+
value = mask_keys(api_hash, key)
|
79
79
|
if value.is_a?(Contrast::Config::ApiProxyConfiguration)
|
80
80
|
Contrast::Config.validate_proxy(value)
|
81
81
|
elsif value.is_a?(Contrast::Config::CertificationConfiguration)
|
@@ -92,31 +92,31 @@ module Contrast
|
|
92
92
|
end
|
93
93
|
|
94
94
|
def self.validate_proxy config
|
95
|
-
puts
|
95
|
+
puts("Proxy Enabled: #{ config.enable }")
|
96
96
|
return unless config.enable
|
97
97
|
|
98
|
-
puts
|
98
|
+
puts("Proxy URL: #{ config.url }")
|
99
99
|
abort('Proxy Enabled but no Proxy URL given') unless config.url
|
100
100
|
end
|
101
101
|
|
102
102
|
def self.validate_cert config
|
103
|
-
puts
|
103
|
+
puts("Certification Enabled: #{ config.enable }")
|
104
104
|
return unless config.enable
|
105
105
|
|
106
|
-
puts
|
106
|
+
puts("CA File: #{ config.ca_file }")
|
107
107
|
abort('CA file path not provided') unless config.ca_file
|
108
|
-
puts
|
108
|
+
puts("Cert File: #{ config.cert_file }")
|
109
109
|
abort('Cert file path not provided') unless config.cert_file
|
110
|
-
puts
|
110
|
+
puts("Key File: #{ config.key_file }")
|
111
111
|
abort('Key file path not provided') unless config.key_file
|
112
112
|
end
|
113
113
|
|
114
114
|
def self.validate_audit config
|
115
|
-
puts
|
115
|
+
puts("Request Audit Enabled: #{ config.enable }")
|
116
116
|
return unless config.enable
|
117
117
|
|
118
118
|
config.each do |k, v|
|
119
|
-
puts
|
119
|
+
puts("#{ k }::#{ v }")
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
@@ -125,7 +125,7 @@ module Contrast
|
|
125
125
|
reporter = Contrast::Agent::Reporter.new
|
126
126
|
reporter_headers = reporter.client.headers.to_hash
|
127
127
|
reporter_headers.each_key do |key|
|
128
|
-
value = mask_keys
|
128
|
+
value = mask_keys(reporter_headers, key)
|
129
129
|
missing << key if value.nil?
|
130
130
|
end
|
131
131
|
abort("Missing required header values: #{ missing.join(', ') }") unless missing.empty?
|
@@ -135,13 +135,13 @@ module Contrast
|
|
135
135
|
def self.test_connection reporter
|
136
136
|
connection = reporter.connection
|
137
137
|
abort('Failed to Initialize Connection please check error logs for details') unless connection
|
138
|
-
abort('Failed to Start Client please check error logs for details') unless reporter.client.startup!
|
138
|
+
abort('Failed to Start Client please check error logs for details') unless reporter.client.startup!(connection)
|
139
139
|
end
|
140
140
|
|
141
141
|
def self.mask_keys hash, key
|
142
142
|
value = hash[key]
|
143
143
|
redacted_value = Contrast::Configuration::REDACTED if SKIP_LOG.include?(key.to_s)
|
144
|
-
puts
|
144
|
+
puts("#{ key }::#{ redacted_value || value }") unless value.is_a?(Contrast::Config::BaseConfiguration)
|
145
145
|
value
|
146
146
|
end
|
147
147
|
end
|
@@ -11,7 +11,7 @@ module Contrast
|
|
11
11
|
extend Rake::DSL
|
12
12
|
# Start the service if it is not already running
|
13
13
|
def self.start_service
|
14
|
-
puts
|
14
|
+
puts('Starting Contrast Service')
|
15
15
|
service_log = ::Contrast::CONTRAST_SERVICE.logger_path
|
16
16
|
if File.writable?(service_log)
|
17
17
|
spawn('contrast_service', out: File::NULL, err: service_log)
|
@@ -23,7 +23,7 @@ module Contrast
|
|
23
23
|
sleep(0.05) until Contrast::Utils::OS.running?
|
24
24
|
end
|
25
25
|
watcher.join(1)
|
26
|
-
puts
|
26
|
+
puts(Contrast::Utils::OS.running? ? 'Contrast Service started successfully.' : 'Contrast Service did not start.')
|
27
27
|
end
|
28
28
|
|
29
29
|
# Stop the service if it is running
|