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