contrast-agent 3.8.5 → 3.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/cs__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
data/ext/cs__scope/cs__scope.h
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
#include <ruby.h>
|
|
2
|
-
|
|
3
|
-
VALUE rbzero = INT2NUM(0);
|
|
4
|
-
VALUE scope_class;
|
|
5
|
-
VALUE rb_sym_new;
|
|
6
|
-
|
|
7
|
-
const char *ivar_contrast_scope;
|
|
8
|
-
|
|
9
|
-
VALUE CONTRAST_SCOPE;
|
|
10
|
-
|
|
11
|
-
VALUE in_given_scope(const VALUE object, const char *scope);
|
|
12
|
-
|
|
13
|
-
void enter_given_scope(const VALUE object, const char *scope);
|
|
14
|
-
|
|
15
|
-
void exit_given_scope(const VALUE object, const char *scope);
|
|
16
|
-
|
|
17
|
-
VALUE in_contrast_scope(const VALUE self);
|
|
18
|
-
|
|
19
|
-
VALUE enter_contrast_scope(const VALUE self);
|
|
20
|
-
|
|
21
|
-
VALUE exit_contrast_scope(const VALUE self);
|
|
22
|
-
|
|
23
|
-
VALUE run_in_scope(const VALUE self);
|
|
24
|
-
|
|
25
|
-
VALUE enter_scope_for(const VALUE self, const VALUE scope_symbol);
|
|
26
|
-
|
|
27
|
-
VALUE exit_scope_for(const VALUE self, const VALUE scope_symbol);
|
|
28
|
-
|
|
29
|
-
VALUE initialize(const VALUE self);
|
|
30
|
-
|
|
31
|
-
VALUE deep_clone(const VALUE self);
|
|
32
|
-
|
|
33
|
-
void Init_cs__scope(void);
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/components/interface'
|
|
5
|
-
cs__scoped_require 'contrast/core_extensions/module'
|
|
6
|
-
cs__scoped_require 'contrast/utils/object_share'
|
|
7
|
-
|
|
8
|
-
module Contrast
|
|
9
|
-
module Agent
|
|
10
|
-
module Assess
|
|
11
|
-
# This is used to revert, or undo, the patches that we've placed into
|
|
12
|
-
# modules. This is necessary for those cases where the original method
|
|
13
|
-
# was supposed to be removed, but wasn't b/c we had renamed it -- looking
|
|
14
|
-
# at you, FactoryBot
|
|
15
|
-
class ClassReverter
|
|
16
|
-
include Contrast::Components::Interface
|
|
17
|
-
access_component :logging, :scope
|
|
18
|
-
|
|
19
|
-
class << self
|
|
20
|
-
def unpatch!
|
|
21
|
-
Contrast::Agent::FeatureState.instance.uninstrument_namespaces.
|
|
22
|
-
each { |mod_sym| revert_module mod_sym }
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
private
|
|
26
|
-
|
|
27
|
-
def revert_module mod
|
|
28
|
-
with_contrast_scope do
|
|
29
|
-
revert_child_modules(mod, [])
|
|
30
|
-
end
|
|
31
|
-
rescue StandardError => e
|
|
32
|
-
logger.error(e, "Unable to remove patches from the module #{ mod }")
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def revert_child_modules mod, reverted_modules, parent_mod = nil
|
|
36
|
-
return if parent_mod == mod
|
|
37
|
-
return if reverted_modules.include?(mod)
|
|
38
|
-
|
|
39
|
-
reverted_modules << mod
|
|
40
|
-
|
|
41
|
-
immediate_constants = mod.cs__constants(false).collect! { |k| mod.cs__const_get(k) }
|
|
42
|
-
immediate_constants.select! { |k| k.is_a?(Module) }
|
|
43
|
-
immediate_constants.flatten!
|
|
44
|
-
if immediate_constants.any?
|
|
45
|
-
immediate_constants.each do |const|
|
|
46
|
-
revert_aliases(const)
|
|
47
|
-
revert_child_modules(const, reverted_modules, mod)
|
|
48
|
-
end
|
|
49
|
-
else
|
|
50
|
-
revert_aliases(mod)
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# in order to fully uninstrument classes we must use true when getting the singleton/instance methods
|
|
55
|
-
# that way if a class makes use of instance_eval for instance(defined on Kernel) we are able to revert this
|
|
56
|
-
# specific instance of that method to use the default behavior while leaving the remainder of
|
|
57
|
-
# objects using the patched behavior
|
|
58
|
-
def revert_aliases clazz
|
|
59
|
-
marker = Contrast::Utils::ObjectShare::CONTRAST_PATCHED_METHOD_START
|
|
60
|
-
instance_methods = (clazz.instance_methods(true) + clazz.private_instance_methods(true)).select { |method| method.to_s.start_with?(marker) }
|
|
61
|
-
singleton_methods = clazz.cs__singleton_class.instance_methods(true).select { |method| method.to_s.start_with?(marker) }
|
|
62
|
-
instance_methods.each { |i_method| revert_alias(clazz, i_method, instance_methods) }
|
|
63
|
-
singleton_methods.each { |s_method| revert_alias(clazz.cs__singleton_class, s_method, singleton_methods) }
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def revert_alias clazz, current_method_name, methods
|
|
67
|
-
original_method_name = clazz.instance_method(current_method_name).original_name
|
|
68
|
-
|
|
69
|
-
is_private = clazz.private_method_defined?(original_method_name)
|
|
70
|
-
|
|
71
|
-
# revert aliasing only for those methods currently defined on the original
|
|
72
|
-
if is_private || clazz.method_defined?(original_method_name)
|
|
73
|
-
clazz.send(:alias_method, original_method_name, current_method_name)
|
|
74
|
-
clazz.send(:private, original_method_name) if is_private
|
|
75
|
-
end
|
|
76
|
-
clazz.send(:undef_method, current_method_name) if methods.include?(current_method_name)
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/agent/assess/class_reverter'
|
|
5
|
-
cs__scoped_require 'contrast/components/interface'
|
|
6
|
-
|
|
7
|
-
module Contrast
|
|
8
|
-
module Agent
|
|
9
|
-
module Patching
|
|
10
|
-
module Policy
|
|
11
|
-
# This is how we unpatch out of our customer's code. It provides a way
|
|
12
|
-
# to remove ourselves from those modules which have since had their
|
|
13
|
-
# definition of the patched method revoked, such as when running with
|
|
14
|
-
# FactoryBot
|
|
15
|
-
module PolicyUnpatcher
|
|
16
|
-
include Contrast::Components::Interface
|
|
17
|
-
access_component :logging
|
|
18
|
-
|
|
19
|
-
def self.revert_conflicting_patches
|
|
20
|
-
logger.debug_with_time("\t\tRunning reversions") do
|
|
21
|
-
Contrast::Agent::Assess::ClassReverter.unpatch!
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/utils/object_share'
|
|
5
|
-
|
|
6
|
-
# Some developers override various methods on Module, which can often involve
|
|
7
|
-
# changing expected method parity/behavior which in turn prevents us from being
|
|
8
|
-
# able to reliably use affected methods. Let's alias these method so that we
|
|
9
|
-
# always have access to them.
|
|
10
|
-
class Module
|
|
11
|
-
alias_method :cs__name, :name
|
|
12
|
-
alias_method :cs__constants, :constants
|
|
13
|
-
alias_method :cs__const_defined?, :const_defined?
|
|
14
|
-
alias_method :cs__const_get, :const_get
|
|
15
|
-
alias_method :cs__const_set, :const_set
|
|
16
|
-
alias_method :cs__autoload?, :autoload?
|
|
17
|
-
|
|
18
|
-
# The method const_defined? can cause autoload, which is bad for us. The
|
|
19
|
-
# method autoload? doesn't traverse namespaces. This method lets us provide a
|
|
20
|
-
# constant, as a String, and parse it to determine if it has been truly
|
|
21
|
-
# truly defined, meaning it existed before this method was invoked, not as a
|
|
22
|
-
# result of it.
|
|
23
|
-
#
|
|
24
|
-
# @param name [String] the name of the constant to look up
|
|
25
|
-
# @return [Boolean]
|
|
26
|
-
def cs__truly_defined? name
|
|
27
|
-
return false unless name
|
|
28
|
-
|
|
29
|
-
segments = name.split(Contrast::Utils::ObjectShare::DOUBLE_COLON)
|
|
30
|
-
previous_module = Module
|
|
31
|
-
segments.each do |segment|
|
|
32
|
-
return false if previous_module.cs__autoload?(segment)
|
|
33
|
-
return false unless previous_module.cs__const_defined?(segment)
|
|
34
|
-
|
|
35
|
-
previous_module = previous_module.cs__const_get(segment)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
true
|
|
39
|
-
rescue NameError # account for nonsense / poorly formatted constants
|
|
40
|
-
false
|
|
41
|
-
end
|
|
42
|
-
end
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/utils/object_share'
|
|
5
|
-
|
|
6
|
-
# Some aliases within Object have to happen especially early, because they're
|
|
7
|
-
# core to class definitions. See lib/contrast.rb.
|
|
8
|
-
# ONLY very core aliasing should go there. All the routine extension should
|
|
9
|
-
# happen here, where you'd expect it.
|
|
10
|
-
class Object
|
|
11
|
-
# Return a String representing the self invoking this method.
|
|
12
|
-
def cs__inspect
|
|
13
|
-
if cs__is_a?(String)
|
|
14
|
-
return Contrast::Utils::ObjectShare::EMPTY_STRING if empty?
|
|
15
|
-
|
|
16
|
-
dup
|
|
17
|
-
elsif cs__is_a?(Symbol)
|
|
18
|
-
":#{ self }"
|
|
19
|
-
elsif cs__is_a?(Numeric)
|
|
20
|
-
to_s
|
|
21
|
-
elsif cs__is_a?(Module)
|
|
22
|
-
"#{ cs__name }@#{ __id__ }"
|
|
23
|
-
else
|
|
24
|
-
"#{ cs__class.cs__name }@#{ __id__ }"
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
end
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
if defined?(ActionController) &&
|
|
5
|
-
defined?(ActionController::Railties) &&
|
|
6
|
-
defined?(ActionController::Railties::Helpers)
|
|
7
|
-
module ActionController
|
|
8
|
-
module Railties
|
|
9
|
-
# Used to monkey patch all the inherited calls in action_pack
|
|
10
|
-
#
|
|
11
|
-
# This is the usual entry point for Rails inheritance work, so it should
|
|
12
|
-
# catch most of the calls to inherited.
|
|
13
|
-
module Helpers
|
|
14
|
-
alias_method :cs__patched_inherited, :inherited
|
|
15
|
-
def inherited klass
|
|
16
|
-
klass&.instance_variable_set(:@cs__defining_class, true)
|
|
17
|
-
cs__patched_inherited(klass)
|
|
18
|
-
ensure
|
|
19
|
-
klass&.instance_variable_set(:@cs__defining_class, false)
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
if defined?(ActiveRecord) &&
|
|
27
|
-
defined?(ActiveRecord::AttributeMethods) &&
|
|
28
|
-
defined?(ActiveRecord::AttributeMethods::TimeZoneConversion) &&
|
|
29
|
-
defined?(ActiveRecord::AttributeMethods::TimeZoneConversion::ClassMethods)
|
|
30
|
-
module ActiveRecord
|
|
31
|
-
module AttributeMethods
|
|
32
|
-
# Used to monkey patch all the inherited calls in action_pack
|
|
33
|
-
module TimeZoneConversion
|
|
34
|
-
module ClassMethods #:nodoc:
|
|
35
|
-
private
|
|
36
|
-
|
|
37
|
-
alias_method :cs__patched_inherited, :inherited
|
|
38
|
-
def inherited klass
|
|
39
|
-
klass&.instance_variable_set(:@cs__defining_class, true)
|
|
40
|
-
cs__patched_inherited(klass)
|
|
41
|
-
ensure
|
|
42
|
-
klass&.instance_variable_set(:@cs__defining_class, false)
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
if defined?(ActiveRecord) &&
|
|
5
|
-
defined?(ActiveRecord::AttributeMethods) &&
|
|
6
|
-
defined?(ActiveRecord::AttributeMethods::Read) &&
|
|
7
|
-
defined?(ActiveRecord::AttributeMethods::Read::ClassMethods)
|
|
8
|
-
|
|
9
|
-
module ActiveRecord
|
|
10
|
-
module AttributeMethods
|
|
11
|
-
module Read
|
|
12
|
-
# Rails / ActiveRecord are sneaky a.f. They define attributes of a
|
|
13
|
-
# class in one method, then monkey patch allocate in another and
|
|
14
|
-
# finally invoke module_eval in this method... but of course they use a
|
|
15
|
-
# '_tmp_' header for the method name and then alias it in this module
|
|
16
|
-
# to name it what we expect
|
|
17
|
-
module ClassMethods
|
|
18
|
-
alias_method :cs__patched_define_method_attribute, :define_method_attribute
|
|
19
|
-
|
|
20
|
-
def define_method_attribute *args, &block
|
|
21
|
-
ret = cs__patched_define_method_attribute(*args, &block)
|
|
22
|
-
method_name = args[0]
|
|
23
|
-
Contrast::Agent::Assess::Policy::Patcher.patch_assess_method(self, method_name)
|
|
24
|
-
ret
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
protected :cs__patched_define_method_attribute, :define_method_attribute
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/components/interface'
|
|
5
|
-
|
|
6
|
-
if defined?(ActiveRecord) &&
|
|
7
|
-
defined?(ActiveRecord::Scoping) &&
|
|
8
|
-
defined?(ActiveRecord::Scoping::Named) &&
|
|
9
|
-
defined?(ActiveRecord::Scoping::Named::ClassMethods) &&
|
|
10
|
-
ActiveRecord::Scoping::Named::ClassMethods.
|
|
11
|
-
instance_methods(false).
|
|
12
|
-
include?(:scope)
|
|
13
|
-
module ActiveRecord
|
|
14
|
-
module Scoping
|
|
15
|
-
module Named
|
|
16
|
-
# Our patch into the ActiveRecord::Scoping::Named::ClassMethods Module,
|
|
17
|
-
# allowing for the runtime rewrite of interpolation calls defined in
|
|
18
|
-
# methods defined dynamically during application execution.
|
|
19
|
-
#
|
|
20
|
-
# TODO: RUBY-534
|
|
21
|
-
module ClassMethods
|
|
22
|
-
include Contrast::Components::Interface
|
|
23
|
-
access_component :logging, :agent
|
|
24
|
-
|
|
25
|
-
def _cs__rewrite method_name, body
|
|
26
|
-
return body unless AGENT.rewrite_interpolation?
|
|
27
|
-
return body unless body.is_a?(Proc)
|
|
28
|
-
|
|
29
|
-
location = body.source_location
|
|
30
|
-
return body if location.nil?
|
|
31
|
-
|
|
32
|
-
# Good news, once we patch the body once, the source location
|
|
33
|
-
# becomes eval. We may need to fix this later though (so it may
|
|
34
|
-
# be bad news)
|
|
35
|
-
return body if location.empty? || location[0].empty? || location[0].include?('eval')
|
|
36
|
-
|
|
37
|
-
opener = Contrast::Agent::ClassReopener.new(Contrast::Agent::ModuleData.new(self))
|
|
38
|
-
original_source_code = opener.source_code(location, method_name)
|
|
39
|
-
return body unless original_source_code
|
|
40
|
-
return body if Contrast::Agent::Rewriter.send(:unrepeatable?, original_source_code)
|
|
41
|
-
return body unless Contrast::Agent::Rewriter.send(:interpolations?, original_source_code)
|
|
42
|
-
|
|
43
|
-
# the code looks like 'source :some_method_name, ->lambda_literal'
|
|
44
|
-
# we just need the lambda
|
|
45
|
-
body_start = original_source_code.index(',') + 1
|
|
46
|
-
original_source_code = original_source_code[body_start..-1]
|
|
47
|
-
|
|
48
|
-
new_method_source = Contrast::Agent::Rewriter.send(:rewrite_method, original_source_code)
|
|
49
|
-
return body unless Contrast::Agent::Rewriter.send(:valid_code?, new_method_source)
|
|
50
|
-
|
|
51
|
-
unbound_eval(cs__name, new_method_source)
|
|
52
|
-
rescue SyntaxError, StandardError => e
|
|
53
|
-
logger.debug(e, "Can't parse method source in scoped method #{ method_name }: #{ e.message }")
|
|
54
|
-
body
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
cs__scoped_require 'cs__assess_active_record_named/cs__assess_active_record_named'
|
|
61
|
-
end
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: false
|
|
3
|
-
|
|
4
|
-
if defined?(Rails) && defined?(Rails::Application) && defined?(Rails::Application::Configuration)
|
|
5
|
-
module Rails
|
|
6
|
-
class Application
|
|
7
|
-
# Our patch into the Rails::Application::Configuration Class, allowing
|
|
8
|
-
# for the runtime detection of insecure configurations on individual
|
|
9
|
-
# ActionDispatch::Session::AbstractStore instances within the
|
|
10
|
-
# application.
|
|
11
|
-
class Configuration
|
|
12
|
-
include Contrast::Utils::InvalidConfigurationUtil
|
|
13
|
-
include Contrast::Components::Interface
|
|
14
|
-
|
|
15
|
-
access_component :analysis, :scope
|
|
16
|
-
|
|
17
|
-
alias_method :cs__patched_session_store, :session_store
|
|
18
|
-
def session_store *args
|
|
19
|
-
ret = cs__patched_session_store(*args)
|
|
20
|
-
Contrast::Utils::RailsAssessConfiguration.analyze_session_store(*args)
|
|
21
|
-
ret
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
cs__scoped_require 'contrast/components/interface'
|
|
5
|
-
|
|
6
|
-
if defined?(ActionController) && defined?(ActionController::Live) && defined?(ActionController::Live::Buffer)
|
|
7
|
-
module ActionController
|
|
8
|
-
module Live
|
|
9
|
-
# This class acts as our patch into the ActionController::Live::Buffer
|
|
10
|
-
# class, allowing us to track the close event on streamed responses.
|
|
11
|
-
class Buffer
|
|
12
|
-
include Contrast::Components::Interface
|
|
13
|
-
access_component :contrast_service
|
|
14
|
-
|
|
15
|
-
# normally pre->in->post filters are applied however, in a streamed response
|
|
16
|
-
# we can run into a case where it's pre -> in -> post -> more infilters
|
|
17
|
-
# in order to submit anything found during the infilters after the response has been written we need to explicity send them
|
|
18
|
-
alias_method :cs__close, :close
|
|
19
|
-
def close
|
|
20
|
-
if (context = Contrast::Agent::REQUEST_TRACKER.current)
|
|
21
|
-
[context.server_activity, context.activity, context.observed_route].each do |msg|
|
|
22
|
-
CONTRAST_SERVICE.send_message msg
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
cs__close
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
if defined?(Rack)
|
|
5
|
-
# In earlier versions of rack < 2.0.0 the Rack::Response and Rack::Request do
|
|
6
|
-
# not have get_header or set_header methods. This is our way of working
|
|
7
|
-
# around that.
|
|
8
|
-
module Rack
|
|
9
|
-
if defined?(Rack::Request)
|
|
10
|
-
# Our patch into the Rack::Request class, allowing us to call set_header
|
|
11
|
-
# and get_header in our code without worrying about older versions of
|
|
12
|
-
# Rack not implementing these methods.
|
|
13
|
-
class Request
|
|
14
|
-
unless Rack::Request.instance_methods(true).include?(:set_header)
|
|
15
|
-
def set_header name, value
|
|
16
|
-
@env[name] = value
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
unless Rack::Request.instance_methods(true).include?(:get_header)
|
|
20
|
-
def get_header name
|
|
21
|
-
@env[name]
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
if defined?(Rack::Response)
|
|
28
|
-
# Our patch into the Rack::Response Class, allowing us to call set_header
|
|
29
|
-
# and get_header in our code without worrying about older versions of
|
|
30
|
-
# Rack not implementing these methods.
|
|
31
|
-
class Response
|
|
32
|
-
unless Rack::Response.instance_methods(true).include?(:set_header)
|
|
33
|
-
def set_header key, value
|
|
34
|
-
headers[key] = value
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
unless Rack::Response.instance_methods(true).include?(:get_header)
|
|
38
|
-
def get_header key
|
|
39
|
-
headers[key]
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|