contrast-agent 7.1.0 → 7.2.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/extconf_common.rb +88 -14
- data/lib/contrast/agent/assess/policy/source_method.rb +13 -4
- data/lib/contrast/agent/assess/policy/trigger_method.rb +12 -18
- data/lib/contrast/agent/excluder/excluder.rb +64 -31
- data/lib/contrast/agent/protect/rule/base.rb +4 -6
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker.rb +1 -1
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +2 -2
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +1 -1
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization/deserialization.rb +2 -2
- data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +1 -1
- data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +1 -1
- data/lib/contrast/agent/protect/rule/utils/filters.rb +6 -6
- data/lib/contrast/agent/protect/rule/xxe/xxe.rb +1 -1
- data/lib/contrast/agent/reporting/client/interface.rb +132 -0
- data/lib/contrast/agent/reporting/client/interface_base.rb +27 -0
- data/lib/contrast/agent/reporting/connection_status.rb +0 -1
- data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +6 -4
- data/lib/contrast/agent/reporting/reporter.rb +11 -26
- data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +10 -3
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +47 -6
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +40 -31
- data/lib/contrast/agent/reporting/reporting_utilities/resend.rb +144 -0
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +35 -13
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_mode.rb +14 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +11 -11
- data/lib/contrast/agent/request/request.rb +27 -12
- data/lib/contrast/agent/telemetry/base.rb +18 -19
- data/lib/contrast/agent/telemetry/exception/obfuscate.rb +97 -0
- data/lib/contrast/agent/telemetry/exception.rb +1 -0
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/components/config/sources.rb +6 -5
- data/lib/contrast/components/settings.rb +9 -0
- data/lib/contrast/config/diagnostics/source_config_value.rb +5 -1
- data/lib/contrast/config/diagnostics/tools.rb +4 -4
- data/lib/contrast/config/validate.rb +2 -2
- data/lib/contrast/configuration.rb +11 -19
- data/lib/contrast/framework/grape/support.rb +1 -2
- data/lib/contrast/framework/manager.rb +17 -8
- data/lib/contrast/framework/rack/support.rb +99 -1
- data/lib/contrast/framework/rails/support.rb +1 -2
- data/lib/contrast/framework/sinatra/support.rb +1 -2
- data/lib/contrast/logger/aliased_logging.rb +18 -9
- data/lib/contrast/utils/hash_utils.rb +21 -2
- data/lib/contrast/utils/request_utils.rb +14 -0
- data/resources/assess/policy.json +11 -0
- metadata +6 -3
- data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1a9469e29e067a8c67e64a771b3d60522c4999ecd1133fdc96c3f6c9ff528f71
|
4
|
+
data.tar.gz: 8cbed6cbdf60a9017c80f0edbd5bbe11ea104620ae606f2eac5db4d2c930667f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ba2a3f4887a593a5b61544ce6622df70cfe54d1a6b7fe6c4e57927714ab5b6c16ccf13b8c7cd703acb0f55e405c6bcb8e55c781e6f7171d087dc48885942a33
|
7
|
+
data.tar.gz: 7d791ee31ffe0857ac51a6d26f7489baf986f3b4445cc697f202df3ab47dd77c2e484a2516ca2ed442afbfe9be02e8139dab2a866dcc0358210774a6c1e33ca9
|
data/ext/extconf_common.rb
CHANGED
@@ -5,6 +5,31 @@ require 'mkmf'
|
|
5
5
|
require 'rbconfig'
|
6
6
|
require_relative '../lib/contrast/agent/version'
|
7
7
|
|
8
|
+
# Create explicit symbol list, that will be set as promise to be loaded dynamic on run time.
|
9
|
+
SYMS = %w[
|
10
|
+
_assess
|
11
|
+
_policy
|
12
|
+
_assess_policy
|
13
|
+
_assess_propagator
|
14
|
+
_core_assess
|
15
|
+
_contrast_patcher
|
16
|
+
_contrast_check_prepended
|
17
|
+
_contrast_check_and_register_instance_patch
|
18
|
+
_contrast_register_singleton_prepend_patch
|
19
|
+
_contrast_register_patch
|
20
|
+
_contrast_register_singleton_patch
|
21
|
+
_inst_methods_enter_cntr_scope
|
22
|
+
_inst_methods_enter_method_scope
|
23
|
+
_inst_methods_exit_cntr_scope
|
24
|
+
_inst_methods_exit_method_scope
|
25
|
+
_inst_methods_in_cntr_scope
|
26
|
+
_rb_sym_method
|
27
|
+
_rb_sym_hash_tracked
|
28
|
+
_rb_sym_skip_assess_analysis
|
29
|
+
_rb_sym_skip_contrast_analysis
|
30
|
+
_patch_via_funchook
|
31
|
+
].freeze # rubocop:disable Security/Object/Freeze
|
32
|
+
|
8
33
|
# The mkmf.rb file uses all passed flags from Ruby configuration (RbConfig::CONFIG) on
|
9
34
|
# Ruby build time. Problem with Clang and GCC is that it do not keep up with c89 and finds
|
10
35
|
# error on including <ryby.h> as not allowing inline variables.
|
@@ -32,8 +57,7 @@ require_relative '../lib/contrast/agent/version'
|
|
32
57
|
STANDARD_FLAGS = '-std=gnu89'
|
33
58
|
CLANG = 'clang'
|
34
59
|
|
35
|
-
#
|
36
|
-
# Note: Adding -pedantic could raise <ruby.h> warnings, and we are not in control of that code.
|
60
|
+
# Adding -pedantic could raise <ruby.h> warnings, and we are not in control of that code.
|
37
61
|
# e.g. error: '_Bool' is a C99 extension [-Werror,-Wc99-extensions] ; empty macros and etc.
|
38
62
|
#
|
39
63
|
# -Wno-int-conversion => Passing VALUEs as function args but required as unsigned long parameters.
|
@@ -55,8 +79,19 @@ WARNING_FLAGS = %w[
|
|
55
79
|
# Flags that are only recognized by gcc:
|
56
80
|
GCC_FLAGS = %w[-Wno-maybe-uninitialized].freeze # rubocop:disable Security/Object/Freeze
|
57
81
|
|
82
|
+
def darwin?
|
83
|
+
RbConfig::CONFIG['target_os'].include?('darwin')
|
84
|
+
end
|
85
|
+
|
58
86
|
# Extend $CFLAGS passed directly to compiler in ruby mkmf
|
87
|
+
#
|
88
|
+
# Extended flags are mainly tested with clang and gcc. Experience with other compilers may vary.
|
89
|
+
# To that end if something brakes on client side we must have a mechanism to go back to previous
|
90
|
+
# non strict gnu89 standard and be able to maintain the build.
|
91
|
+
# We can disable newly added changes with this setting CONTRAST_USE_C89=false.
|
59
92
|
def extend_cflags
|
93
|
+
return if ENV['CONTRAST__USE_GNU89'] == 'false'
|
94
|
+
|
60
95
|
$CFLAGS += " #{ [STANDARD_FLAGS, WARNING_FLAGS].flatten.join(' ') }"
|
61
96
|
# Extend with GCC specific flags:
|
62
97
|
unless RbConfig::MAKEFILE_CONFIG['CC'].downcase.include?(CLANG) ||
|
@@ -67,6 +102,52 @@ def extend_cflags
|
|
67
102
|
end
|
68
103
|
end
|
69
104
|
|
105
|
+
# use C compiler if set.
|
106
|
+
def enable_env_cc
|
107
|
+
RbConfig::CONFIG['CC'] = RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
|
108
|
+
end
|
109
|
+
|
110
|
+
# Since we cannot link directly the bundles created after the extensions being build,
|
111
|
+
# we can pass flags to the linker to resolve symbols not being found during compilation,
|
112
|
+
# since they are going to be available on load time. Ruby first is loaded then the extensions.
|
113
|
+
# MacOS introduced new fixups with Xcode 14. This causes the issue of symbols not being linked during
|
114
|
+
# compilation for the Agent, and other ruby related issues with objective C objects being used,
|
115
|
+
# bigdecimal being different and so on.
|
116
|
+
#
|
117
|
+
# Ruby itself is build on MacOS with '--enabled-shared' flag, also Ruby interpreters compiled
|
118
|
+
# under Xcode14 no longer specify by default in DLDFLAGS this flag:
|
119
|
+
#
|
120
|
+
# '-undefined dynamic_lookup'
|
121
|
+
# ( As of Xcode14.3 behavior of dynamic_lookup is reverted back.)
|
122
|
+
#
|
123
|
+
# This simply is telling the linker that any unknown symbols will be resolved dynamic on extension load.
|
124
|
+
# However with the new fixup chain introduced an warning may be produced:
|
125
|
+
# ld: warning: -undefined dynamic_lookup may not work with chained fixups.
|
126
|
+
# The fixups are responsible for the dynamic linking of the dylibs.
|
127
|
+
def mac_symbol_resolve
|
128
|
+
# If this is braking the build, it can be disabled.
|
129
|
+
return if ENV['CONTRAST__NO_MAC_LD_FIX'] == 'true'
|
130
|
+
return unless darwin?
|
131
|
+
|
132
|
+
# Disabled as of the unknown changes to newly ruby interpreter builds:
|
133
|
+
# RbConfig::CONFIG['EXTDLDFLAGS'] = "-bundle_loader #{ RbConfig::CONFIG['EXTDLDFLAGS'] }"
|
134
|
+
|
135
|
+
# Avoid using this, as not desirable:
|
136
|
+
#
|
137
|
+
# Adding -no_fixup_chains will brake older compilers but will work on newer.
|
138
|
+
# This flag solves the problem but on the long run might not be the solution needed, now not being default,
|
139
|
+
# any new feature changes on Mac or Ruby side might brake things again.
|
140
|
+
# Use this only if explicitly set as ENV var,as a backup on client's end.
|
141
|
+
#
|
142
|
+
# $LDFLAGS << " " << flag
|
143
|
+
append_ldflags('-Wl,-no_fixup_chains -undefined dynamic_lookup') if ENV['CONTRAST__MAC_LD_USE_ALT'] == 'true'
|
144
|
+
|
145
|
+
# Another alternative is to use -Wl,-U with explicit listed depending symbols.
|
146
|
+
# Append the symfile:
|
147
|
+
SYMS.each { |sym| $DLDFLAGS << " -Wl,-U,#{ sym }" } unless ENV['CONTRAST__MAC_LD_USE_ALT'] == 'true'
|
148
|
+
end
|
149
|
+
|
150
|
+
# Generate Makefile.
|
70
151
|
def make!
|
71
152
|
create_makefile("#{ $TO_MAKE }/#{ $TO_MAKE }")
|
72
153
|
end
|
@@ -75,9 +156,9 @@ end
|
|
75
156
|
# | MOVING CODE BELLOW THIS SECTION MAY BRAKE MAKEFILE. ORDER MATTERS! |
|
76
157
|
# ----------------------------------------------------------------------
|
77
158
|
|
159
|
+
# __dir__ is relative to the file you're reading.
|
160
|
+
# this file you're reading is presently within $APP_ROOT/ext/.
|
78
161
|
def ext_path
|
79
|
-
# __dir__ is relative to the file you're reading.
|
80
|
-
# this file you're reading is presently within $APP_ROOT/ext/.
|
81
162
|
__dir__
|
82
163
|
end
|
83
164
|
|
@@ -85,14 +166,7 @@ end
|
|
85
166
|
# funchook.h file. Then we can pass CFLAGS and extend makefile flags and invoke make!
|
86
167
|
require_relative './build_funchook'
|
87
168
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
# We can disable newly added changes with this setting CONTRAST_USE_C89=false.
|
92
|
-
extend_cflags unless ENV['CONTRAST__USE_GNU89'] == 'false'
|
93
|
-
|
94
|
-
# use same C compiler if set.
|
95
|
-
RbConfig::CONFIG['CC'] = RbConfig::MAKEFILE_CONFIG['CC'] = ENV['CC'] if ENV['CC']
|
96
|
-
|
97
|
-
# Generate Makefile.
|
169
|
+
enable_env_cc
|
170
|
+
mac_symbol_resolve
|
171
|
+
extend_cflags
|
98
172
|
make!
|
@@ -43,6 +43,7 @@ module Contrast
|
|
43
43
|
return unless analyze?(method_policy, object, ret, args)
|
44
44
|
return if event_limit?(method_policy)
|
45
45
|
return unless (source_node = method_policy.source_node)
|
46
|
+
# Exclusions makes method slow:
|
46
47
|
return if excluded_by_url?
|
47
48
|
|
48
49
|
# used to hold the object and ret
|
@@ -76,6 +77,7 @@ module Contrast
|
|
76
77
|
|
77
78
|
source_name ||= determine_source_name(source_node, source_data.object, source_data.ret, *args)
|
78
79
|
|
80
|
+
# Exclusions makes method slow:
|
79
81
|
return if excluded_by_input?(source_type, source_name)
|
80
82
|
|
81
83
|
# We know we only work on certain things.
|
@@ -188,16 +190,23 @@ module Contrast
|
|
188
190
|
#
|
189
191
|
# @return [Boolean]
|
190
192
|
def excluded_by_input? source_type, source_name
|
191
|
-
|
192
|
-
Contrast::
|
193
|
+
return false unless Contrast::SETTINGS.excluder.exclusions.any?
|
194
|
+
return false unless Contrast::Agent::REQUEST_TRACKER.current
|
195
|
+
# skip if the source is collection, it will be evaluated by it's elements. Collections are not
|
196
|
+
# trackable.
|
197
|
+
return false if source_name.cs__is_a?(Hash)
|
198
|
+
|
199
|
+
Contrast::SETTINGS.excluder.assess_excluded_by_input?(source_type, source_name)
|
193
200
|
end
|
194
201
|
|
195
202
|
# Should a source be excluded because it matches one of the url exclusion rules?
|
196
203
|
#
|
197
204
|
# @return [Boolean]
|
198
205
|
def excluded_by_url?
|
199
|
-
|
200
|
-
Contrast::
|
206
|
+
return false unless Contrast::SETTINGS.excluder.exclusions.any?
|
207
|
+
return false unless Contrast::Agent::REQUEST_TRACKER.current
|
208
|
+
|
209
|
+
Contrast::SETTINGS.excluder.assess_excluded_by_url?
|
201
210
|
end
|
202
211
|
end
|
203
212
|
end
|
@@ -93,11 +93,11 @@ module Contrast
|
|
93
93
|
|
94
94
|
request = find_request(source)
|
95
95
|
return unless reportable?(request&.env)
|
96
|
-
return if excluded_by_url_and_rule?(
|
96
|
+
return if excluded_by_url_and_rule?(trigger_node.rule_id)
|
97
97
|
|
98
98
|
finding = Contrast::Agent::Reporting::Finding.new(trigger_node.rule_id)
|
99
99
|
finding.attach_data(trigger_node, source, object, ret, request, *args)
|
100
|
-
return if excluded_by_input_and_rule?(
|
100
|
+
return if excluded_by_input_and_rule?(finding, trigger_node.rule_id)
|
101
101
|
|
102
102
|
finding.hash_code = Contrast::Utils::HashDigest.generate_event_hash(finding, source, request)
|
103
103
|
check_for_stored_xss(finding)
|
@@ -167,28 +167,22 @@ module Contrast
|
|
167
167
|
end
|
168
168
|
end
|
169
169
|
|
170
|
-
def build_events finding, event
|
171
|
-
return unless event
|
172
|
-
|
173
|
-
event.parent_events&.each do |parent_event|
|
174
|
-
build_events(finding, parent_event)
|
175
|
-
end
|
176
|
-
# events could technically be nil, but we would have failed the rule check before getting here. not
|
177
|
-
# worth the nil check
|
178
|
-
finding.events << event.to_dtm_event
|
179
|
-
end
|
180
|
-
|
181
170
|
# Check if the finding should be excluded due to the assess exclusion rules.
|
182
171
|
#
|
183
|
-
# @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
|
184
172
|
# @param rule_id [String]
|
185
173
|
# return [Boolean]
|
186
|
-
def excluded_by_url_and_rule?
|
187
|
-
Contrast::SETTINGS.excluder.
|
174
|
+
def excluded_by_url_and_rule? rule_id
|
175
|
+
return false unless Contrast::SETTINGS.excluder.exclusions.any?
|
176
|
+
return unless Contrast::Agent::REQUEST_TRACKER.current
|
177
|
+
|
178
|
+
Contrast::SETTINGS.excluder.assess_excluded_by_url_and_rule?(rule_id)
|
188
179
|
end
|
189
180
|
|
190
|
-
def excluded_by_input_and_rule?
|
191
|
-
Contrast::SETTINGS.excluder.
|
181
|
+
def excluded_by_input_and_rule? finding, rule_id
|
182
|
+
return false unless Contrast::SETTINGS.excluder.exclusions.any?
|
183
|
+
return unless Contrast::Agent::REQUEST_TRACKER.current
|
184
|
+
|
185
|
+
Contrast::SETTINGS.excluder.assess_excluded_by_input_and_rule?(finding, rule_id)
|
192
186
|
end
|
193
187
|
|
194
188
|
# Handles the Stored Xss rule. If a vector is stored in the database
|
@@ -3,6 +3,8 @@
|
|
3
3
|
|
4
4
|
require 'contrast/agent/reporting/settings/url_exclusion'
|
5
5
|
require 'contrast/agent/reporting/input_analysis/input_type'
|
6
|
+
require 'contrast/utils/object_share'
|
7
|
+
require 'contrast/utils/assess/object_store'
|
6
8
|
|
7
9
|
module Contrast
|
8
10
|
module Agent
|
@@ -19,11 +21,14 @@ module Contrast
|
|
19
21
|
@exclusions = exclusions
|
20
22
|
end
|
21
23
|
|
24
|
+
def cached_paths
|
25
|
+
@_cached_paths ||= Contrast::Utils::Assess::ObjectStore.new(10)
|
26
|
+
end
|
27
|
+
|
22
28
|
# Determine if an input is excluded for protect rule.
|
23
29
|
#
|
24
30
|
# @param results [Array<Contrast::Agent::Reporting::InputAnalysisResult>]
|
25
|
-
|
26
|
-
def protect_excluded_by_input? results, request_path
|
31
|
+
def protect_excluded_by_input? results
|
27
32
|
return false unless results.any?
|
28
33
|
|
29
34
|
exclusion_matched = 0
|
@@ -35,8 +40,7 @@ module Contrast
|
|
35
40
|
|
36
41
|
# Based on strategy:
|
37
42
|
match = input_match_strategy(exclusion_match,
|
38
|
-
input_match?(exclusion_match, rule_result.input_type, rule_result.key)
|
39
|
-
request_path)
|
43
|
+
input_match?(exclusion_match, rule_result.input_type, rule_result.key))
|
40
44
|
exclusion_matched += 1 if match
|
41
45
|
end
|
42
46
|
end
|
@@ -48,25 +52,21 @@ module Contrast
|
|
48
52
|
# If an assess URL exclusion rule applies to the current url, *and* is defined as "All Rules"
|
49
53
|
# then we can avoid any tracking for the request.
|
50
54
|
#
|
51
|
-
# @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
|
52
55
|
# @return [Boolean]
|
53
|
-
def assess_excluded_by_url?
|
56
|
+
def assess_excluded_by_url?
|
54
57
|
assess_url_exclusions_for_all_rules.any? do |exclusion_matcher|
|
55
|
-
path_match?(exclusion_matcher
|
58
|
+
path_match?(exclusion_matcher)
|
56
59
|
end
|
57
60
|
end
|
58
61
|
|
59
62
|
# If an assess URL exclusion rule applies to the current url, *and* also covers the
|
60
63
|
# provided rule_id, then we can avoid tracking this entry.
|
61
64
|
#
|
62
|
-
# @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
|
63
65
|
# @param rule_id [String]
|
64
66
|
# return [Boolean]
|
65
|
-
def assess_excluded_by_url_and_rule?
|
66
|
-
request_path = request.path
|
67
|
-
|
67
|
+
def assess_excluded_by_url_and_rule?rule_id
|
68
68
|
assess_url_exclusions.any? do |exclusion_matcher|
|
69
|
-
path_match?(exclusion_matcher
|
69
|
+
path_match?(exclusion_matcher) &&
|
70
70
|
(exclusion_matcher.assess_rules.empty? || exclusion_matcher.assess_rules.include?(rule_id))
|
71
71
|
end
|
72
72
|
end
|
@@ -74,35 +74,30 @@ module Contrast
|
|
74
74
|
# If an assess INPUT exclusion rule applies to the current url, *and* also covers all
|
75
75
|
# rules, then we can avoid tracking this entry.
|
76
76
|
#
|
77
|
-
# @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
|
78
77
|
# @param source_type [String]
|
79
78
|
# @param source_name [String]
|
80
79
|
# return [Boolean]
|
81
|
-
def assess_excluded_by_input?
|
82
|
-
request_path = request.path
|
83
|
-
|
80
|
+
def assess_excluded_by_input?source_type, source_name
|
84
81
|
assess_input_exclusions_for_all_rules.any? do |exclusion_matcher|
|
85
|
-
input_match?(exclusion_matcher, source_type, source_name) && path_match?(exclusion_matcher
|
82
|
+
input_match?(exclusion_matcher, source_type, source_name) && path_match?(exclusion_matcher)
|
86
83
|
end
|
87
84
|
end
|
88
85
|
|
89
86
|
# If an assess INPUT exclusion rule covers the provided rule_id *for all finding event sources*, then we
|
90
87
|
# can avoid tracking this entry. If any event source *isn't excluded* then we don't exclude the finding.
|
91
88
|
#
|
92
|
-
# @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
|
93
89
|
# @param finding [Contrast::Agent::Reporting::Finding]
|
94
90
|
# @param rule [String]
|
95
91
|
# return [Boolean]
|
96
|
-
def assess_excluded_by_input_and_rule?
|
92
|
+
def assess_excluded_by_input_and_rule?finding, rule
|
97
93
|
return false if finding.events.empty?
|
98
94
|
|
99
95
|
# We need to check for url exclusions here for the input rules as the url exclusions
|
100
96
|
# that have already been checked didn't include the INPUT exclusions. So we look for
|
101
97
|
# any INPUT exclusions that apply to the current url and the supplied rule.
|
102
|
-
path = request.path
|
103
98
|
rule_input_exclusions = assess_input_exclusions.select do |exclusion_matcher|
|
104
99
|
(exclusion_matcher.protect_rules.empty? || exclusion_matcher.protect_rules.include?(rule)) &&
|
105
|
-
path_match?(exclusion_matcher
|
100
|
+
path_match?(exclusion_matcher)
|
106
101
|
end
|
107
102
|
return false if rule_input_exclusions.empty?
|
108
103
|
|
@@ -122,13 +117,12 @@ module Contrast
|
|
122
117
|
# then we can avoid using the rule for the request.
|
123
118
|
#
|
124
119
|
# @param rule_id [String]
|
125
|
-
# @param path [String]
|
126
120
|
# return [Boolean]
|
127
|
-
def protect_excluded_by_url? rule_id
|
121
|
+
def protect_excluded_by_url? rule_id
|
128
122
|
protect_url_exclusions.any? do |exclusion_matcher|
|
129
123
|
next unless exclusion_matcher.protection_rule?(rule_id)
|
130
124
|
|
131
|
-
return true if path_match?(exclusion_matcher
|
125
|
+
return true if path_match?(exclusion_matcher)
|
132
126
|
end
|
133
127
|
end
|
134
128
|
|
@@ -140,14 +134,13 @@ module Contrast
|
|
140
134
|
#
|
141
135
|
# @param exclusion_match [Contrast::Agent::ExclusionMatcher]
|
142
136
|
# @param input_match [Boolean] does the input match the exclusion
|
143
|
-
# @param request_path [String] Current request path
|
144
137
|
# @return [Boolean]
|
145
|
-
def input_match_strategy exclusion_match, input_match
|
138
|
+
def input_match_strategy exclusion_match, input_match
|
146
139
|
# for ALL urls
|
147
140
|
return input_match if exclusion_match.match_all?
|
148
141
|
|
149
142
|
# for ONLY match we need to check if there is an input and url match.
|
150
|
-
input_match && path_match?(exclusion_match
|
143
|
+
input_match && path_match?(exclusion_match)
|
151
144
|
end
|
152
145
|
|
153
146
|
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
@@ -202,12 +195,25 @@ module Contrast
|
|
202
195
|
end
|
203
196
|
end
|
204
197
|
|
198
|
+
# Returns true if context.request.path matches any url exclusion.
|
199
|
+
#
|
205
200
|
# @return [Boolean]
|
206
|
-
def path_match? exclusion_matcher
|
207
|
-
return false unless path
|
201
|
+
def path_match? exclusion_matcher
|
202
|
+
return false unless Contrast::Agent::REQUEST_TRACKER.current&.request&.path
|
203
|
+
|
204
|
+
return_cached_result(exclusion_matcher)
|
205
|
+
matches = 0
|
206
|
+
matches += 1 if exclusion_matcher.wildcard_url
|
207
|
+
exclusion_matcher.urls.any? do |url|
|
208
|
+
if url.match?(Contrast::Agent::REQUEST_TRACKER.current.request.path) ||
|
209
|
+
regexp_match?(url, Contrast::Agent::REQUEST_TRACKER.current.request.path)
|
210
|
+
|
211
|
+
matches += 1
|
212
|
+
end
|
213
|
+
end
|
208
214
|
|
209
|
-
exclusion_matcher
|
210
|
-
|
215
|
+
add_cached_path(exclusion_matcher, matches)
|
216
|
+
matches.positive?
|
211
217
|
end
|
212
218
|
|
213
219
|
# @param exclusion [Contrast::Agent::ExclusionMatcher]
|
@@ -301,6 +307,33 @@ module Contrast
|
|
301
307
|
def cookie_types
|
302
308
|
@_cookie_types ||= [COOKIE_NAME, COOKIE_VALUE].cs__freeze
|
303
309
|
end
|
310
|
+
|
311
|
+
# Adds new cached result unless it already exists
|
312
|
+
#
|
313
|
+
# @param exclusion_matcher [Contrast::Agent::ExclusionMatcher]
|
314
|
+
# @param matches [Boolean] the result of last iteration
|
315
|
+
# @return [Hash, nil]
|
316
|
+
def add_cached_path exclusion_matcher, matches
|
317
|
+
return if cached_paths[Contrast::Agent::REQUEST_TRACKER.current.request.path.__id__]
|
318
|
+
|
319
|
+
cached_paths[Contrast::Agent::REQUEST_TRACKER.
|
320
|
+
current.request.path.__id__] = { matcher: exclusion_matcher.__id__, result: matches.positive? }
|
321
|
+
rescue StandardError
|
322
|
+
nil
|
323
|
+
end
|
324
|
+
|
325
|
+
# returns a cached result if current path and matcher are the same.
|
326
|
+
# @param exclusion_matcher [Contrast::Agent::ExclusionMatcher]
|
327
|
+
# @return [Boolean, nil]
|
328
|
+
def return_cached_result exclusion_matcher
|
329
|
+
return unless !cached_paths[Contrast::Agent::REQUEST_TRACKER.current.request.path.__id__].nil? &&
|
330
|
+
(cached_paths[Contrast::Agent::REQUEST_TRACKER.current.
|
331
|
+
request.path.__id__][:matcher] == exclusion_matcher.__id__)
|
332
|
+
|
333
|
+
cached_paths[Contrast::Agent::REQUEST_TRACKER.current.request.path.__id__][:result]
|
334
|
+
rescue StandardError
|
335
|
+
nil
|
336
|
+
end
|
304
337
|
end
|
305
338
|
end
|
306
339
|
end
|
@@ -166,17 +166,15 @@ module Contrast
|
|
166
166
|
# Check if the protect rules is excluded by url from the exclusion rules for this application.
|
167
167
|
#
|
168
168
|
# @param rule_id [String]
|
169
|
-
|
170
|
-
|
171
|
-
Contrast::SETTINGS.excluder.protect_excluded_by_url?(rule_id, request_path)
|
169
|
+
def protect_excluded_by_url? rule_id
|
170
|
+
Contrast::SETTINGS.excluder.protect_excluded_by_url?(rule_id)
|
172
171
|
end
|
173
172
|
|
174
173
|
# Check if the protect rules is excluded by input from the exclusion rules for this application.
|
175
174
|
#
|
176
175
|
# @param results [Array<Contrast::Agent::Reporting::InputAnalysis>]
|
177
|
-
|
178
|
-
|
179
|
-
Contrast::SETTINGS.excluder.protect_excluded_by_input?(results, request_path)
|
176
|
+
def protect_excluded_by_input? results
|
177
|
+
Contrast::SETTINGS.excluder.protect_excluded_by_input?(results)
|
180
178
|
end
|
181
179
|
|
182
180
|
# Allows for the InputAnalysis from Agent Library to be extracted early
|
@@ -77,7 +77,7 @@ module Contrast
|
|
77
77
|
# @return [Contrast::Agent::Reporting::RaspRuleSample]
|
78
78
|
def build_sample context, ia_result, _candidate_string, **_kwargs
|
79
79
|
sample = build_base_sample(context, ia_result)
|
80
|
-
sample.details = Contrast::Agent::Reporting::BotBlockerDetails.new
|
80
|
+
sample.details = Contrast::Agent::Reporting::Details::BotBlockerDetails.new
|
81
81
|
sample.details.bot = ia_result.value
|
82
82
|
sample.details.user_agent = context&.request&.user_agent
|
83
83
|
sample
|
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
require 'contrast/agent/reporting/input_analysis/input_type'
|
5
5
|
require 'contrast/agent/reporting/input_analysis/score_level'
|
6
|
-
require 'contrast/agent/reporting/
|
6
|
+
require 'contrast/agent/reporting/details/bot_blocker_details'
|
7
7
|
require 'contrast/utils/input_classification_base'
|
8
8
|
require 'contrast/utils/object_share'
|
9
9
|
|
@@ -73,7 +73,7 @@ module Contrast
|
|
73
73
|
if score >= THRESHOLD
|
74
74
|
ia_result.score_level = DEFINITEATTACK
|
75
75
|
ia_result.ids << BOT_BLOCKER_MATCH
|
76
|
-
ia_result.details = Contrast::Agent::Reporting::BotBlockerDetails.new
|
76
|
+
ia_result.details = Contrast::Agent::Reporting::Details::BotBlockerDetails.new
|
77
77
|
# details:
|
78
78
|
add_details(ia_result, value)
|
79
79
|
else
|
@@ -37,7 +37,7 @@ module Contrast
|
|
37
37
|
# @raise [Contrast::SecurityException] if the rule mode ise set
|
38
38
|
# to BLOCK and valid cdmi is detected.
|
39
39
|
def infilter context, classname, method, command
|
40
|
-
return if protect_excluded_by_url?(rule_name
|
40
|
+
return if protect_excluded_by_url?(rule_name)
|
41
41
|
return unless backdoors_match?(command)
|
42
42
|
return unless (result = build_attack_with_match(context, nil, nil, command,
|
43
43
|
**{ classname: classname, method: method }))
|
@@ -43,7 +43,7 @@ module Contrast
|
|
43
43
|
# to BLOCK and valid cdmi is detected.
|
44
44
|
def infilter context, classname, method, command
|
45
45
|
return unless infilter?(command)
|
46
|
-
return if protect_excluded_by_url?(rule_name
|
46
|
+
return if protect_excluded_by_url?(rule_name)
|
47
47
|
return unless (result = build_violation(context, command))
|
48
48
|
|
49
49
|
append_to_activity(context, result)
|
@@ -58,9 +58,9 @@ module Contrast
|
|
58
58
|
# Per the spec, this rule applies regardless of input. Only the mode
|
59
59
|
# of the rule and code exclusions apply at this point.
|
60
60
|
# @return [Boolean] should the rule apply to this call.
|
61
|
-
def infilter?
|
61
|
+
def infilter?_context
|
62
62
|
return false unless enabled?
|
63
|
-
return false if protect_excluded_by_url?(rule_name
|
63
|
+
return false if protect_excluded_by_url?(rule_name)
|
64
64
|
|
65
65
|
true
|
66
66
|
end
|
data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb
CHANGED
@@ -46,7 +46,7 @@ module Contrast
|
|
46
46
|
# @raise [Contrast::SecurityException] if the rule mode ise set
|
47
47
|
# to BLOCK and valid cdmi is detected.
|
48
48
|
def infilter context, method, path
|
49
|
-
return if protect_excluded_by_url?(rule_name
|
49
|
+
return if protect_excluded_by_url?(rule_name)
|
50
50
|
return unless rule_violated?(path)
|
51
51
|
|
52
52
|
result = build_violation(context, path)
|
@@ -19,7 +19,7 @@ module Contrast
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def infilter context, sql_query
|
22
|
-
return false if protect_excluded_by_url?(rule_name
|
22
|
+
return false if protect_excluded_by_url?(rule_name)
|
23
23
|
return unless violated?(sql_query)
|
24
24
|
|
25
25
|
result = build_violation(context, sql_query)
|
@@ -42,8 +42,8 @@ module Contrast
|
|
42
42
|
return false unless context
|
43
43
|
return false unless enabled?
|
44
44
|
return false unless (results = gather_ia_results(context)) && results.any?
|
45
|
-
return false if protect_excluded_by_url?(rule_name
|
46
|
-
return false if protect_excluded_by_input?(results
|
45
|
+
return false if protect_excluded_by_url?(rule_name)
|
46
|
+
return false if protect_excluded_by_input?(results)
|
47
47
|
|
48
48
|
true
|
49
49
|
end
|
@@ -68,8 +68,8 @@ module Contrast
|
|
68
68
|
def infilter? context
|
69
69
|
return false unless enabled?
|
70
70
|
return false unless (results = gather_ia_results(context)) && results.any?
|
71
|
-
return false if protect_excluded_by_url?(rule_name
|
72
|
-
return false if protect_excluded_by_input?(results
|
71
|
+
return false if protect_excluded_by_url?(rule_name)
|
72
|
+
return false if protect_excluded_by_input?(results)
|
73
73
|
|
74
74
|
true
|
75
75
|
end
|
@@ -89,8 +89,8 @@ module Contrast
|
|
89
89
|
# @raise [Contrast::SecurityException]
|
90
90
|
def postfilter context
|
91
91
|
return unless enabled? && POSTFILTER_MODES.include?(mode)
|
92
|
-
return false if protect_excluded_by_url?(rule_name
|
93
|
-
return if protect_excluded_by_input?(gather_ia_results(context)
|
92
|
+
return false if protect_excluded_by_url?(rule_name)
|
93
|
+
return if protect_excluded_by_input?(gather_ia_results(context))
|
94
94
|
|
95
95
|
return if mode == :NO_ACTION || mode == :PERMIT
|
96
96
|
|
@@ -37,7 +37,7 @@ module Contrast
|
|
37
37
|
# @raise [Contrast::SecurityException] Security exception if an XXE
|
38
38
|
# attack is found and the rule is in block mode.
|
39
39
|
def infilter context, framework, xml
|
40
|
-
return if protect_excluded_by_url?(rule_name
|
40
|
+
return if protect_excluded_by_url?(rule_name)
|
41
41
|
|
42
42
|
result = find_attacker(context, xml, framework: framework)
|
43
43
|
return unless result
|