contrast-agent 3.8.5 → 3.9.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__assess_array/cs__assess_array.c +1 -1
- data/ext/cs__assess_module/cs__assess_module.c +0 -1
- data/ext/cs__assess_yield_track/cs__assess_yield_track.c +34 -0
- data/ext/cs__assess_yield_track/cs__assess_yield_track.h +12 -0
- data/ext/{cs__scope → cs__assess_yield_track}/extconf.rb +0 -0
- data/ext/cs__common/cs__common.c +6 -6
- data/ext/cs__common/cs__common.h +3 -1
- data/ext/cs__contrast_patch/cs__contrast_patch.c +142 -119
- data/ext/cs__contrast_patch/cs__contrast_patch.h +3 -0
- data/funchook/autom4te.cache/requests +48 -48
- data/funchook/config.log +2 -2
- data/lib/contrast/agent.rb +15 -5
- data/lib/contrast/agent/assess.rb +0 -1
- data/lib/contrast/agent/assess/contrast_event.rb +9 -8
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +68 -18
- data/lib/contrast/agent/assess/policy/policy.rb +0 -14
- data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
- data/lib/contrast/agent/assess/policy/preshift.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagation_method.rb +4 -2
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
- data/lib/contrast/agent/assess/policy/propagator/splat.rb +2 -2
- data/lib/contrast/agent/assess/policy/propagator/split.rb +166 -1
- data/lib/contrast/agent/assess/policy/rewriter_patch.rb +1 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +199 -140
- data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +30 -0
- data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +36 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +238 -153
- data/lib/contrast/agent/assess/policy/trigger_node.rb +54 -9
- data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +13 -0
- data/lib/contrast/agent/assess/properties.rb +29 -0
- data/lib/contrast/agent/assess/rule/csrf/csrf_applicator.rb +35 -31
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +1 -1
- data/lib/contrast/agent/class_reopener.rb +98 -55
- data/lib/contrast/agent/feature_state.rb +1 -1
- data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
- data/lib/contrast/agent/logger_manager.rb +2 -2
- data/lib/contrast/agent/middleware.rb +1 -3
- data/lib/contrast/agent/patching/policy/after_load_patch.rb +40 -4
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +33 -8
- data/lib/contrast/agent/patching/policy/method_policy.rb +20 -7
- data/lib/contrast/agent/patching/policy/patch.rb +54 -23
- data/lib/contrast/agent/patching/policy/patch_status.rb +0 -2
- data/lib/contrast/agent/patching/policy/patcher.rb +10 -11
- data/lib/contrast/agent/patching/policy/policy.rb +4 -0
- data/lib/contrast/agent/patching/policy/policy_node.rb +14 -1
- data/lib/contrast/agent/patching/policy/trigger_node.rb +2 -1
- data/lib/contrast/agent/protect/policy/policy.rb +6 -6
- data/lib/contrast/agent/protect/rule/base.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization.rb +3 -25
- data/lib/contrast/agent/protect/rule/sqli.rb +1 -1
- data/lib/contrast/agent/railtie.rb +11 -5
- data/lib/contrast/agent/request.rb +1 -19
- data/lib/contrast/agent/request_context.rb +1 -1
- data/lib/contrast/agent/rewriter.rb +4 -3
- data/lib/contrast/agent/scope.rb +116 -19
- data/lib/contrast/agent/service_heartbeat.rb +5 -2
- data/lib/contrast/agent/settings_state.rb +12 -8
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api.rb +1 -0
- data/lib/contrast/api/speedracer.rb +2 -2
- data/lib/contrast/components/agent.rb +26 -7
- data/lib/contrast/components/app_context.rb +8 -45
- data/lib/contrast/components/contrast_service.rb +3 -4
- data/lib/contrast/components/interface.rb +1 -1
- data/lib/contrast/components/scope.rb +56 -26
- data/lib/contrast/config/ruby_configuration.rb +8 -3
- data/lib/contrast/delegators.rb +9 -0
- data/lib/contrast/delegators/application_update.rb +32 -0
- data/lib/contrast/extensions/framework/rack/cookie.rb +24 -0
- data/lib/contrast/extensions/framework/rack/request.rb +24 -0
- data/lib/contrast/extensions/framework/rack/response.rb +23 -0
- data/lib/contrast/extensions/framework/rails/action_controller_railties_helper_inherited.rb +20 -0
- data/lib/contrast/extensions/framework/rails/active_record.rb +26 -0
- data/lib/contrast/extensions/framework/rails/active_record_named.rb +53 -0
- data/lib/contrast/extensions/framework/rails/active_record_time_zone_inherited.rb +21 -0
- data/lib/contrast/extensions/framework/rails/buffer.rb +28 -0
- data/lib/contrast/extensions/framework/rails/configuration.rb +27 -0
- data/lib/contrast/extensions/framework/sinatra/base.rb +59 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess.rb +12 -11
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/array.rb +4 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/assess_extension.rb +0 -2
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/basic_object.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/erb.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/exec_trigger.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/fiber.rb +3 -4
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/hash.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/kernel.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/module.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/regexp.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/string.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/assess/tilt_template_trigger.rb +0 -0
- data/lib/contrast/extensions/ruby_core/assess/xpath_library_trigger.rb +40 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/delegator.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/eval_trigger.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/inventory/datastores.rb +1 -1
- data/lib/contrast/extensions/ruby_core/module.rb +17 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_command_injection_rule.rb +8 -6
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_deserialization_rule.rb +7 -5
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_no_sqli_rule.rb +5 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_path_traversal_rule.rb +31 -27
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_sqli_rule.rb +5 -3
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/applies_xxe_rule.rb +9 -7
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/kernel.rb +0 -0
- data/lib/contrast/{core_extensions → extensions/ruby_core}/protect/psych.rb +1 -1
- data/lib/contrast/{core_extensions → extensions/ruby_core}/thread.rb +0 -0
- data/lib/contrast/framework/base_support.rb +63 -0
- data/lib/contrast/framework/manager.rb +109 -0
- data/lib/contrast/framework/platform_version.rb +21 -0
- data/lib/contrast/framework/rails_support.rb +88 -0
- data/lib/contrast/framework/sinatra_application_helper.rb +49 -0
- data/lib/contrast/framework/sinatra_support.rb +94 -0
- data/lib/contrast/framework/view_technologies_descriptor.rb +20 -0
- data/lib/contrast/utils/assess/tracking_util.rb +2 -4
- data/lib/contrast/utils/class_util.rb +92 -37
- data/lib/contrast/utils/duck_utils.rb +59 -39
- data/lib/contrast/utils/environment_util.rb +5 -75
- data/lib/contrast/utils/freeze_util.rb +3 -7
- data/lib/contrast/utils/invalid_configuration_util.rb +5 -5
- data/lib/contrast/utils/job_servers_running.rb +39 -0
- data/lib/contrast/utils/ruby_ast_rewriter.rb +2 -2
- data/lib/contrast/utils/service_response_util.rb +0 -6
- data/lib/contrast/utils/sinatra_helper.rb +6 -0
- data/lib/contrast/utils/stack_trace_utils.rb +1 -1
- data/resources/assess/policy.json +74 -23
- data/resources/inventory/policy.json +1 -1
- data/resources/protect/policy.json +11 -9
- data/resources/rubocops/object/frozen_cop.rb +1 -1
- data/ruby-agent.gemspec +2 -0
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +94 -57
- data/ext/cs__scope/cs__scope.c +0 -96
- data/ext/cs__scope/cs__scope.h +0 -33
- data/lib/contrast/agent/assess/class_reverter.rb +0 -82
- data/lib/contrast/agent/patching/policy/policy_unpatcher.rb +0 -28
- data/lib/contrast/core_extensions/module.rb +0 -42
- data/lib/contrast/core_extensions/object.rb +0 -27
- data/lib/contrast/rails_extensions/assess/action_controller_inheritance.rb +0 -48
- data/lib/contrast/rails_extensions/assess/active_record.rb +0 -32
- data/lib/contrast/rails_extensions/assess/active_record_named.rb +0 -61
- data/lib/contrast/rails_extensions/assess/configuration.rb +0 -26
- data/lib/contrast/rails_extensions/buffer.rb +0 -30
- data/lib/contrast/rails_extensions/rack.rb +0 -45
- data/lib/contrast/sinatra_extensions/assess/cookie.rb +0 -26
- data/lib/contrast/sinatra_extensions/inventory/sinatra_base.rb +0 -59
- data/lib/contrast/utils/operating_environment.rb +0 -38
- data/lib/contrast/utils/path_util.rb +0 -151
- data/lib/contrast/utils/scope_util.rb +0 -99
@@ -126,6 +126,10 @@ module Contrast
|
|
126
126
|
triggers.select { |trigger| trigger.rule_id == rule_id }
|
127
127
|
end
|
128
128
|
|
129
|
+
def find_source_node class_name, method_name, instance_method
|
130
|
+
sources.find { |source| source.class_name == class_name && source.method_name == method_name && source.instance_method == instance_method }
|
131
|
+
end
|
132
|
+
|
129
133
|
def find_node rule_id, class_name, method_name, instance_method
|
130
134
|
find_triggers_by_rule(rule_id).find do |node|
|
131
135
|
node.class_name == class_name && node.method_name == method_name && node.instance_method == instance_method
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
cs__scoped_require 'contrast/components/interface'
|
5
|
+
|
4
6
|
module Contrast
|
5
7
|
module Agent
|
6
8
|
module Patching
|
@@ -10,7 +12,10 @@ module Contrast
|
|
10
12
|
#
|
11
13
|
# @abstract
|
12
14
|
class PolicyNode
|
13
|
-
|
15
|
+
include Contrast::Components::Interface
|
16
|
+
access_component :scope
|
17
|
+
|
18
|
+
attr_accessor :class_name, :instance_method, :method_name, :method_scope, :method_visibility
|
14
19
|
attr_reader :properties
|
15
20
|
|
16
21
|
def node_class
|
@@ -25,6 +30,7 @@ module Contrast
|
|
25
30
|
@class_name = policy_hash[JSON_CLASS_NAME]
|
26
31
|
@instance_method = policy_hash[JSON_INSTANCE_METHOD]
|
27
32
|
@method_name = policy_hash[JSON_METHOD_NAME]
|
33
|
+
@method_scope = policy_hash[JSON_METHOD_SCOPE]
|
28
34
|
@method_visibility = policy_hash[JSON_METHOD_VISIBILITY]
|
29
35
|
@properties = policy_hash[JSON_PROPERTIES]
|
30
36
|
symbolize
|
@@ -42,6 +48,11 @@ module Contrast
|
|
42
48
|
raise(ArgumentError, "#{ node_class } #{ id } did not have a proper method name. Unable to create.") unless method_name
|
43
49
|
raise(ArgumentError, "#{ node_class } #{ id } has a non symbol @method_name value. Unable to create.") unless method_name.is_a?(Symbol)
|
44
50
|
raise(ArgumentError, "#{ node_class } #{ id } has a non symbol @method_visibility value. Unable to create.") unless method_visibility.is_a?(Symbol)
|
51
|
+
unless method_scope.nil? || Contrast::Agent::Scope.valid_scope?(method_scope)
|
52
|
+
raise(ArgumentError, "#{ node_class } #{ id } requires an undefined scope. Unable to create.")
|
53
|
+
end
|
54
|
+
|
55
|
+
nil
|
45
56
|
end
|
46
57
|
|
47
58
|
# just turns this into a ruby-ism
|
@@ -64,6 +75,7 @@ module Contrast
|
|
64
75
|
def symbolize
|
65
76
|
@method_name = @method_name.to_sym if @method_name
|
66
77
|
@method_visibility = @method_visibility.to_sym if @method_visibility
|
78
|
+
@method_scope = @method_scope.to_sym if @method_scope
|
67
79
|
end
|
68
80
|
|
69
81
|
# The keys used to read from policy.json to create the individual
|
@@ -71,6 +83,7 @@ module Contrast
|
|
71
83
|
JSON_CLASS_NAME = 'class_name'
|
72
84
|
JSON_INSTANCE_METHOD = 'instance_method'
|
73
85
|
JSON_METHOD_NAME = 'method_name'
|
86
|
+
JSON_METHOD_SCOPE = 'scope'
|
74
87
|
JSON_METHOD_VISIBILITY = 'method_visibility'
|
75
88
|
JSON_PROPERTIES = 'properties'
|
76
89
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
cs__scoped_require 'contrast/
|
4
|
+
cs__scoped_require 'contrast/extensions/ruby_core/module'
|
5
5
|
cs__scoped_require 'contrast/agent/patching/policy/policy_node'
|
6
6
|
|
7
7
|
module Contrast
|
@@ -20,6 +20,7 @@ module Contrast
|
|
20
20
|
JSON_APPLICATOR_METHOD = 'applicator_method'
|
21
21
|
JSON_REQUIRED_PROPS = 'required_properties'
|
22
22
|
JSON_OPTIONAL_PROPS = 'optional_properties'
|
23
|
+
JSON_SCOPE = 'scope'
|
23
24
|
JSON_ON_EXCEPTION = 'on_exception'
|
24
25
|
|
25
26
|
attr_reader :rule_id
|
@@ -4,12 +4,12 @@
|
|
4
4
|
cs__scoped_require 'contrast/agent/patching/policy/policy'
|
5
5
|
|
6
6
|
# classes required by patches in the policy
|
7
|
-
cs__scoped_require 'contrast/
|
8
|
-
cs__scoped_require 'contrast/
|
9
|
-
cs__scoped_require 'contrast/
|
10
|
-
cs__scoped_require 'contrast/
|
11
|
-
cs__scoped_require 'contrast/
|
12
|
-
cs__scoped_require 'contrast/
|
7
|
+
cs__scoped_require 'contrast/extensions/ruby_core/protect/applies_command_injection_rule'
|
8
|
+
cs__scoped_require 'contrast/extensions/ruby_core/protect/applies_deserialization_rule'
|
9
|
+
cs__scoped_require 'contrast/extensions/ruby_core/protect/applies_no_sqli_rule'
|
10
|
+
cs__scoped_require 'contrast/extensions/ruby_core/protect/applies_path_traversal_rule'
|
11
|
+
cs__scoped_require 'contrast/extensions/ruby_core/protect/applies_sqli_rule'
|
12
|
+
cs__scoped_require 'contrast/extensions/ruby_core/protect/applies_xxe_rule'
|
13
13
|
cs__scoped_require 'contrast/agent/protect/policy/trigger_node'
|
14
14
|
|
15
15
|
module Contrast
|
@@ -14,7 +14,7 @@ module Contrast
|
|
14
14
|
class Base
|
15
15
|
include Contrast::Components::Interface
|
16
16
|
|
17
|
-
access_component :logging, :analysis, :settings
|
17
|
+
access_component :logging, :analysis, :settings, :scope
|
18
18
|
|
19
19
|
UNKNOWN_USER_INPUT = Contrast::Api::Dtm::UserInput.new.tap do |user_input|
|
20
20
|
user_input.input_type = :UNKNOWN
|
@@ -90,7 +90,9 @@ module Contrast
|
|
90
90
|
# @raise [Contrast::SecurityException] if attack detected while in
|
91
91
|
# block mode.
|
92
92
|
def check_command_scope gadget_command
|
93
|
-
|
93
|
+
# If we're within 'deserialization scope', then we've got a
|
94
|
+
# deserialization method in our call stack.
|
95
|
+
return unless in_deserialization_scope?
|
94
96
|
|
95
97
|
context = Contrast::Agent::REQUEST_TRACKER.current
|
96
98
|
kwargs = { COMMAND_SCOPE: true }
|
@@ -100,30 +102,6 @@ module Contrast
|
|
100
102
|
raise Contrast::SecurityException.new(self, BLOCK_MESSAGE) if blocked?
|
101
103
|
end
|
102
104
|
|
103
|
-
# I don't know a better way to do this without introducing another
|
104
|
-
# scope.
|
105
|
-
# The policy files are designed around using the Module names, not
|
106
|
-
# the file names, but stack is built using filenames. These are the
|
107
|
-
# files and methods we patch for this rule.
|
108
|
-
#
|
109
|
-
# There's not real test for this since I can't figure out how to get
|
110
|
-
# a command to execute from within the .load methods
|
111
|
-
# Assuming someone else does, this should just work (tested with
|
112
|
-
# Screener and the combination "%w[erb.rb `result']")
|
113
|
-
DESERIALIZER_STACK = [
|
114
|
-
%w[/psych.rb: `load'],
|
115
|
-
%w[/marshal.rb: `load']
|
116
|
-
].cs__freeze
|
117
|
-
# We're considered deserializing if the call stack includes a
|
118
|
-
# reference to the file in which a serializer is defined and
|
119
|
-
# the method of that serializer responsible for deserializing.
|
120
|
-
# @return [Boolean] if the caller indicates deserialization.
|
121
|
-
def deserializing?
|
122
|
-
Kernel.caller.product(DESERIALIZER_STACK).find do |(frame, (class_signature_form, method_signature_form))|
|
123
|
-
frame.end_with?(method_signature_form) && frame.include?(class_signature_form)
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
105
|
protected
|
128
106
|
|
129
107
|
# Build the RaspRuleSample for the detected Deserialization attack.
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
cs__scoped_require 'contrast/
|
4
|
+
cs__scoped_require 'contrast/extensions/ruby_core/protect/applies_sqli_rule'
|
5
5
|
|
6
6
|
module Contrast
|
7
7
|
module Agent
|
@@ -1,24 +1,30 @@
|
|
1
1
|
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
cs__scoped_require 'contrast/utils/
|
4
|
+
cs__scoped_require 'contrast/utils/job_servers_running'
|
5
5
|
|
6
6
|
module Contrast
|
7
7
|
module Agent
|
8
8
|
# A Railtie to allow for the automatic hooking of the Agent into a Rails
|
9
9
|
# application.
|
10
10
|
class Railtie < Rails::Railtie
|
11
|
+
include Contrast::Components::Interface
|
12
|
+
access_component :agent, :app_context, :logging
|
13
|
+
|
11
14
|
initializer 'Contrast Ruby Agent Initializer' do |app|
|
12
15
|
if defined?(Rails) && defined?(Rails.logger)
|
13
16
|
Rails.logger.debug('In railtie ::')
|
14
17
|
Rails.logger.debug(app.middleware.inspect)
|
15
18
|
end
|
16
19
|
|
17
|
-
|
18
|
-
|
20
|
+
# TODO: RUBY-564 This logic is not specific to Rails and should be used more broadly
|
21
|
+
# with all web frameworks. Move this check to be a part of our new initialization
|
22
|
+
# routine.
|
23
|
+
if APP_CONTEXT.instrument_middleware_stack?
|
24
|
+
AGENT.insert_middleware(app)
|
19
25
|
else
|
20
|
-
|
21
|
-
|
26
|
+
Rails.logger.debug('Detected a running job server, skipping Contrast middleware insertion.')
|
27
|
+
logger.debug(nil, "Disabling Contrast for process #{ Process.pid }")
|
22
28
|
end
|
23
29
|
end
|
24
30
|
|
@@ -265,17 +265,7 @@ module Contrast
|
|
265
265
|
http_request.version = '1.1' # currently not in rack request; hard-coding
|
266
266
|
http_request.method = Contrast::Utils::StringUtils.force_utf8(request_method)
|
267
267
|
http_request.raw = Contrast::Utils::StringUtils.force_utf8(@rack_request.path_info)
|
268
|
-
http_request.parsed_connection =
|
269
|
-
http_request.uri = Contrast::Utils::StringUtils.force_utf8(path)
|
270
|
-
http_request.normalized_uri = Contrast::Utils::StringUtils.force_utf8(normalized_uri)
|
271
|
-
http_context = if http_request.uri == Contrast::Utils::ObjectShare::SLASH
|
272
|
-
Contrast::Utils::ObjectShare::SLASH
|
273
|
-
else
|
274
|
-
http_request.uri.split(Contrast::Utils::ObjectShare::SLASH).first
|
275
|
-
end
|
276
|
-
http_request.context = Contrast::Utils::StringUtils.force_utf8(http_context)
|
277
|
-
http_request.path = Contrast::Utils::StringUtils.force_utf8(http_request.uri)
|
278
|
-
http_request.query_string = Contrast::Utils::StringUtils.force_utf8(query_string)
|
268
|
+
http_request.parsed_connection = false
|
279
269
|
end
|
280
270
|
|
281
271
|
def append_params http_request
|
@@ -395,10 +385,6 @@ module Contrast
|
|
395
385
|
@_content_type ||= @rack_request.content_type
|
396
386
|
end
|
397
387
|
|
398
|
-
def path
|
399
|
-
@_path ||= @rack_request.path
|
400
|
-
end
|
401
|
-
|
402
388
|
def request_cookies
|
403
389
|
@_request_cookies ||= @rack_request.cookies
|
404
390
|
end
|
@@ -407,10 +393,6 @@ module Contrast
|
|
407
393
|
@_parameters ||= with_contrast_scope { normalize_params(@rack_request.params) }
|
408
394
|
end
|
409
395
|
|
410
|
-
def base_url
|
411
|
-
@_base_url ||= @rack_request.base_url
|
412
|
-
end
|
413
|
-
|
414
396
|
# End of Rack Request memoized values
|
415
397
|
|
416
398
|
def file_names
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
|
-
# frozen_string_literal:
|
2
|
+
# frozen_string_literal: true
|
3
3
|
|
4
4
|
# intentional -- we're using a << operator here
|
5
5
|
|
@@ -18,8 +18,8 @@ module Contrast
|
|
18
18
|
include Contrast::Components::Interface
|
19
19
|
access_component :logging, :scope
|
20
20
|
|
21
|
-
SELF_DEFINITION = 'def self.'
|
22
|
-
DEFINITION = 'def '
|
21
|
+
SELF_DEFINITION = 'def self.'
|
22
|
+
DEFINITION = 'def '
|
23
23
|
|
24
24
|
class << self
|
25
25
|
def rewrite_class module_data, redo_rewrite = false
|
@@ -95,6 +95,7 @@ module Contrast
|
|
95
95
|
return nil if location.empty? || location[0].empty? || location[0].include?('eval')
|
96
96
|
return nil if opener.written_from_location?(location)
|
97
97
|
|
98
|
+
opener.written_from_location!(location)
|
98
99
|
opener.source_code(location, method_name)
|
99
100
|
rescue SyntaxError
|
100
101
|
logger.debug(nil, "SyntaxError: Can't parse method source from #{ clazz }##{ method_name }")
|
data/lib/contrast/agent/scope.rb
CHANGED
@@ -1,28 +1,125 @@
|
|
1
1
|
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
-
# Scope lets us disable Contrast for certain code calls. We need to do this so
|
5
|
-
# that we don't propagate through our own code.
|
6
|
-
#
|
7
|
-
# Think logging: If you have
|
8
|
-
# something like "The source was '" + source + "'", and source is tracked,
|
9
|
-
# you'll trigger propagation with the + method. This in turn would cause
|
10
|
-
# propagation if you log there "The target ''" + target + "' was propagated'"
|
11
|
-
# Which would then cause another propagation with the '+' method, forever.
|
12
|
-
#
|
13
|
-
# Instead, we should say "If I'm already doing Contrast things, don't track
|
14
|
-
# this"
|
15
|
-
#
|
16
|
-
# NOTE: DO NOT DO ANYTHING IN THIS CLASS THAT COULD RESULT IN A MONKEY PATCHED
|
17
|
-
# ACTION. WE CAN'T ENTER SCOPE BEFORE WE HAVE A SCOPE! YOU HAVE BEEN WARNED!!!
|
18
4
|
module Contrast
|
19
5
|
module Agent
|
6
|
+
# Scope lets us disable Contrast for certain code calls. We need to do this so
|
7
|
+
# that we don't propagate through our own code.
|
8
|
+
#
|
9
|
+
# Think logging: If you have
|
10
|
+
# something like "The source was '" + source + "'", and source is tracked,
|
11
|
+
# you'll trigger propagation with the + method. This in turn would cause
|
12
|
+
# propagation if you log there "The target ''" + target + "' was propagated'"
|
13
|
+
# Which would then cause another propagation with the '+' method, forever.
|
14
|
+
#
|
15
|
+
# Instead, we should say "If I'm already doing Contrast things, don't track
|
16
|
+
# this"
|
20
17
|
class Scope
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
18
|
+
# The following %i[] list is the authoritative list
|
19
|
+
# of scopes. If you define a new symbol here, you'll
|
20
|
+
# get scope methods:
|
21
|
+
# %i[monkey] ->
|
22
|
+
# enter_monkey_scope!
|
23
|
+
# exit_monkey_scope!
|
24
|
+
# in_monkey_scope?
|
25
|
+
# with_monkey_scope { special_monkey_function }
|
26
|
+
SCOPE_LIST = %i[contrast deserialization].cs__freeze
|
27
|
+
|
28
|
+
iv_list = SCOPE_LIST.map { |name| :"@#{ name }_scope" }
|
29
|
+
define_method 'initialize' do
|
30
|
+
iv_list.each do |iv_sym|
|
31
|
+
instance_variable_set(iv_sym, 0)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
SCOPE_LIST.each do |name|
|
36
|
+
iv_sym = :"@#{ name }_scope"
|
37
|
+
|
38
|
+
define_method "in_#{ name }_scope?" do
|
39
|
+
instance_variable_get(iv_sym).positive?
|
40
|
+
end
|
41
|
+
|
42
|
+
enter_method_sym = :"enter_#{ name }_scope!"
|
43
|
+
define_method enter_method_sym do
|
44
|
+
level = instance_variable_get(iv_sym)
|
45
|
+
instance_variable_set(iv_sym, level + 1)
|
46
|
+
end
|
47
|
+
|
48
|
+
exit_method_sym = :"exit_#{ name }_scope!"
|
49
|
+
define_method exit_method_sym do
|
50
|
+
# by design, can go below zero.
|
51
|
+
# every exit/enter pair (regardless of series)
|
52
|
+
# should cancel each other out.
|
53
|
+
#
|
54
|
+
# so we prefer this sequence:
|
55
|
+
# scope = 0
|
56
|
+
# exit = -1
|
57
|
+
# enter = 0
|
58
|
+
# enter = 1
|
59
|
+
# exit = 0
|
60
|
+
# scope = 0
|
61
|
+
#
|
62
|
+
# over this sequence:
|
63
|
+
# scope = 0
|
64
|
+
# exit = 0
|
65
|
+
# enter = 1
|
66
|
+
# enter = 2
|
67
|
+
# exit = 1
|
68
|
+
# scope = 1
|
69
|
+
level = instance_variable_get(iv_sym)
|
70
|
+
instance_variable_set(iv_sym, level - 1)
|
71
|
+
end
|
72
|
+
|
73
|
+
define_method "with_#{ name }_scope" do |*_args, &block|
|
74
|
+
begin
|
75
|
+
send enter_method_sym
|
76
|
+
block.call
|
77
|
+
ensure
|
78
|
+
send exit_method_sym
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Dynamic versions of the above.
|
84
|
+
# These are equivalent, but they're slower and riskier.
|
85
|
+
# Prefer the static methods if you know what scope you need at the call site.
|
86
|
+
def in_scope? name
|
87
|
+
cs__class.ensure_valid_scope! name
|
88
|
+
call = with_contrast_scope { :"in_#{ name }_scope?" }
|
89
|
+
send(call)
|
90
|
+
end
|
91
|
+
|
92
|
+
def enter_scope! name
|
93
|
+
cs__class.ensure_valid_scope! name
|
94
|
+
call = with_contrast_scope { :"enter_#{ name }_scope!" }
|
95
|
+
send(call)
|
96
|
+
end
|
97
|
+
|
98
|
+
def exit_scope! name
|
99
|
+
cs__class.ensure_valid_scope! name
|
100
|
+
call = with_contrast_scope { :"exit_#{ name }_scope!" }
|
101
|
+
send(call)
|
102
|
+
end
|
103
|
+
|
104
|
+
def with_scope name, &block
|
105
|
+
cs__class.ensure_valid_scope! name
|
106
|
+
call = with_contrast_scope { :"with_#{ name }_scope" }
|
107
|
+
send(call, &block)
|
108
|
+
end
|
109
|
+
|
110
|
+
class << self
|
111
|
+
def valid_scope? scope_sym
|
112
|
+
Contrast::Agent::Scope::SCOPE_LIST.include? scope_sym
|
113
|
+
end
|
114
|
+
|
115
|
+
def ensure_valid_scope! scope_sym
|
116
|
+
unless valid_scope? scope_sym # rubocop:disable Style/GuardClause
|
117
|
+
with_contrast_scope do
|
118
|
+
raise NotImplementedError, "Scope '#{ scope_sym.inspect }' is not registered as a scope."
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
25
123
|
end
|
26
124
|
end
|
27
125
|
end
|
28
|
-
cs__scoped_require 'cs__scope/cs__scope'
|
@@ -20,8 +20,7 @@ module Contrast
|
|
20
20
|
loop do
|
21
21
|
begin
|
22
22
|
logger.debug(nil, 'Sending Heartbeat...')
|
23
|
-
|
24
|
-
CONTRAST_SERVICE.queue_message(Contrast::Api::Dtm::Noop.new)
|
23
|
+
CONTRAST_SERVICE.queue_message(poll_message)
|
25
24
|
end
|
26
25
|
sleep REFRESH_INTERVAL_SEC
|
27
26
|
end
|
@@ -29,6 +28,10 @@ module Contrast
|
|
29
28
|
end
|
30
29
|
alias_method :start, :updater_thread
|
31
30
|
|
31
|
+
def poll_message
|
32
|
+
@_poll_message ||= Contrast::Api::Dtm::Poll.new
|
33
|
+
end
|
34
|
+
|
32
35
|
def stop
|
33
36
|
Thread.kill(@_updater_thread) if @_updater_thread&.alive?
|
34
37
|
end
|
@@ -120,16 +120,20 @@ module Contrast
|
|
120
120
|
def send_inventory_message
|
121
121
|
return unless INVENTORY.enabled?
|
122
122
|
|
123
|
-
|
124
|
-
msg.platform = Contrast::Api::Dtm::Platform.new
|
125
|
-
msg.platform.major, msg.platform.minor, msg.platform.build = *Contrast::Utils::EnvironmentUtil.platform
|
123
|
+
app_update_msg = Contrast::Api::Dtm::ApplicationUpdate.new
|
126
124
|
|
127
|
-
|
128
|
-
Contrast::Utils::EnvironmentUtil.
|
129
|
-
Contrast::Utils::EnvironmentUtil.scan_routes(msg)
|
130
|
-
Contrast::Utils::InventoryUtil.append_db_config(msg)
|
125
|
+
# TODO: RUBY-770
|
126
|
+
Contrast::Utils::EnvironmentUtil.add_library_to_app_update(app_update_msg, protobuf_format(CONFIG.root.inventory.tags))
|
131
127
|
|
132
|
-
|
128
|
+
Contrast::Delegators::ApplicationUpdate.new(app_update_msg).instance_eval do
|
129
|
+
append_view_technology_descriptor_data(Contrast::Agent.framework_manager.find_applicable_view_technologies) if INVENTORY.enabled?
|
130
|
+
append_route_coverage_data(Contrast::Agent.framework_manager.find_route_discovery_data) if INVENTORY.enabled?
|
131
|
+
append_platform_version(Contrast::Agent.framework_manager.platform_version)
|
132
|
+
end
|
133
|
+
|
134
|
+
Contrast::Utils::InventoryUtil.append_db_config(app_update_msg)
|
135
|
+
|
136
|
+
CONTRAST_SERVICE.queue_message app_update_msg
|
133
137
|
end
|
134
138
|
|
135
139
|
def present? str
|