contrast-agent 6.7.0 → 6.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +0 -2
- data/.simplecov +0 -1
- data/Rakefile +0 -1
- data/ext/cs__assess_array/cs__assess_array.c +41 -10
- data/ext/cs__assess_array/cs__assess_array.h +4 -1
- data/lib/contrast/agent/assess/policy/trigger_method.rb +2 -2
- data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +1 -1
- data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +1 -1
- data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +1 -1
- data/lib/contrast/agent/excluder.rb +52 -34
- data/lib/contrast/agent/exclusion_matcher.rb +21 -9
- data/lib/contrast/agent/middleware.rb +4 -4
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +6 -0
- data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +146 -127
- data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +20 -0
- data/lib/contrast/agent/protect/policy/rule_applicator.rb +1 -1
- data/lib/contrast/agent/protect/rule/base.rb +45 -53
- data/lib/contrast/agent/protect/rule/base_service.rb +48 -24
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +98 -0
- data/lib/contrast/agent/protect/rule/bot_blocker.rb +81 -0
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +18 -1
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +8 -5
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +22 -22
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_chained_command.rb +69 -0
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_dangerous_path.rb +68 -0
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +2 -58
- data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -1
- data/lib/contrast/agent/protect/rule/deserialization.rb +3 -14
- data/lib/contrast/agent/protect/rule/http_method_tampering/http_method_tampering_input_classification.rb +2 -2
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +0 -11
- data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +29 -34
- data/lib/contrast/agent/protect/rule/no_sqli.rb +25 -18
- data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_input_classification.rb +61 -0
- data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +114 -0
- data/lib/contrast/agent/protect/rule/path_traversal.rb +38 -12
- data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +33 -15
- data/lib/contrast/agent/protect/rule/sqli/sqli_base_rule.rb +0 -14
- data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +2 -62
- data/lib/contrast/agent/protect/rule/sqli.rb +70 -0
- data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +39 -63
- data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +6 -33
- data/lib/contrast/agent/protect/rule/xss/reflected_xss_input_classification.rb +58 -0
- data/lib/contrast/agent/protect/rule/xss.rb +14 -20
- data/lib/contrast/agent/protect/rule/xxe.rb +4 -24
- data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +18 -39
- data/lib/contrast/agent/reporting/attack_result/response_type.rb +9 -9
- data/lib/contrast/agent/reporting/details/ip_denylist_details.rb +10 -2
- data/lib/contrast/agent/reporting/details/virtual_patch_details.rb +8 -2
- data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +27 -0
- data/lib/contrast/agent/reporting/input_analysis/details/protect_rule_details.rb +15 -0
- data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +1 -2
- data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +16 -2
- data/lib/contrast/agent/reporting/masker/masker.rb +2 -0
- data/lib/contrast/agent/reporting/reporter.rb +1 -14
- data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +15 -12
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +3 -3
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +1 -2
- data/lib/contrast/agent/reporting/reporting_events/application_update.rb +0 -2
- data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +0 -1
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +4 -4
- data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +0 -5
- data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +0 -1
- data/lib/contrast/agent/reporting/reporting_events/poll.rb +1 -11
- data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +0 -1
- data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +0 -1
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +2 -2
- data/lib/contrast/agent/reporting/reporting_utilities/response.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +0 -3
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -0
- data/lib/contrast/agent/reporting/settings/code_exclusion.rb +6 -1
- data/lib/contrast/agent/reporting/settings/exclusion_base.rb +18 -0
- data/lib/contrast/agent/reporting/settings/exclusions.rb +2 -1
- data/lib/contrast/agent/reporting/settings/input_exclusion.rb +9 -3
- data/lib/contrast/agent/reporting/settings/protect.rb +15 -15
- data/lib/contrast/agent/request.rb +2 -14
- data/lib/contrast/agent/request_context.rb +6 -9
- data/lib/contrast/agent/request_context_extend.rb +9 -148
- data/lib/contrast/agent/thread_watcher.rb +3 -18
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/agent.rb +0 -11
- data/lib/contrast/agent_lib/api/command_injection.rb +46 -0
- data/lib/contrast/agent_lib/api/init.rb +101 -0
- data/lib/contrast/agent_lib/api/input_tracing.rb +267 -0
- data/lib/contrast/agent_lib/api/method_tempering.rb +29 -0
- data/lib/contrast/agent_lib/api/panic.rb +87 -0
- data/lib/contrast/agent_lib/api/path_semantic_file_security_bypass.rb +40 -0
- data/lib/contrast/agent_lib/interface.rb +260 -0
- data/lib/contrast/agent_lib/interface_base.rb +118 -0
- data/lib/contrast/agent_lib/return_types/eval_result.rb +44 -0
- data/lib/contrast/agent_lib/test.rb +29 -0
- data/lib/contrast/api/communication/connection_status.rb +5 -5
- data/lib/contrast/components/agent.rb +0 -14
- data/lib/contrast/components/app_context.rb +0 -2
- data/lib/contrast/components/app_context_extend.rb +0 -25
- data/lib/contrast/components/config.rb +1 -18
- data/lib/contrast/components/protect.rb +4 -1
- data/lib/contrast/components/ruby_component.rb +1 -1
- data/lib/contrast/components/settings.rb +37 -89
- data/lib/contrast/config/protect_rule_configuration.rb +7 -7
- data/lib/contrast/config/protect_rules_configuration.rb +20 -58
- data/lib/contrast/configuration.rb +1 -10
- data/lib/contrast/extension/assess/array.rb +9 -0
- data/lib/contrast/extension/delegator.rb +2 -0
- data/lib/contrast/framework/manager.rb +3 -1
- data/lib/contrast/framework/rails/railtie.rb +0 -1
- data/lib/contrast/framework/rails/support.rb +0 -1
- data/lib/contrast/tasks/config.rb +1 -8
- data/lib/contrast/utils/duck_utils.rb +1 -0
- data/lib/contrast/utils/input_classification_base.rb +156 -0
- data/lib/contrast/utils/os.rb +0 -20
- data/lib/contrast/utils/response_utils.rb +0 -16
- data/lib/contrast/utils/stack_trace_utils.rb +3 -15
- data/lib/contrast/utils/string_utils.rb +10 -7
- data/lib/contrast.rb +2 -3
- data/resources/protect/policy.json +1 -2
- data/ruby-agent.gemspec +2 -5
- metadata +42 -112
- data/exe/contrast_service +0 -23
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_worth_watching.rb +0 -64
- data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +0 -118
- data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_matcher.rb +0 -45
- data/lib/contrast/agent/reaction_processor.rb +0 -47
- data/lib/contrast/agent/service_heartbeat.rb +0 -35
- data/lib/contrast/api/communication/messaging_queue.rb +0 -128
- data/lib/contrast/api/communication/response_processor.rb +0 -90
- data/lib/contrast/api/communication/service_lifecycle.rb +0 -77
- data/lib/contrast/api/communication/socket.rb +0 -44
- data/lib/contrast/api/communication/socket_client.rb +0 -130
- data/lib/contrast/api/communication/speedracer.rb +0 -138
- data/lib/contrast/api/communication/tcp_socket.rb +0 -32
- data/lib/contrast/api/communication/unix_socket.rb +0 -28
- data/lib/contrast/api/communication.rb +0 -20
- data/lib/contrast/api/decorators/address.rb +0 -59
- data/lib/contrast/api/decorators/agent_startup.rb +0 -56
- data/lib/contrast/api/decorators/application_settings.rb +0 -43
- data/lib/contrast/api/decorators/application_startup.rb +0 -56
- data/lib/contrast/api/decorators/bot_blocker.rb +0 -37
- data/lib/contrast/api/decorators/http_request.rb +0 -137
- data/lib/contrast/api/decorators/input_analysis.rb +0 -18
- data/lib/contrast/api/decorators/instrumentation_mode.rb +0 -35
- data/lib/contrast/api/decorators/ip_denylist.rb +0 -37
- data/lib/contrast/api/decorators/message.rb +0 -67
- data/lib/contrast/api/decorators/rasp_rule_sample.rb +0 -52
- data/lib/contrast/api/decorators/response_type.rb +0 -17
- data/lib/contrast/api/decorators/server_features.rb +0 -25
- data/lib/contrast/api/decorators/user_input.rb +0 -51
- data/lib/contrast/api/decorators/virtual_patch.rb +0 -34
- data/lib/contrast/api/decorators.rb +0 -22
- data/lib/contrast/api/dtm.pb.rb +0 -363
- data/lib/contrast/api/settings.pb.rb +0 -500
- data/lib/contrast/api.rb +0 -16
- data/lib/contrast/components/contrast_service.rb +0 -88
- data/lib/contrast/components/service.rb +0 -55
- data/lib/contrast/tasks/service.rb +0 -84
- data/lib/contrast/utils/input_classification.rb +0 -73
- data/lib/protobuf/code_generator.rb +0 -129
- data/lib/protobuf/decoder.rb +0 -28
- data/lib/protobuf/deprecation.rb +0 -117
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +0 -79
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +0 -360
- data/lib/protobuf/descriptors.rb +0 -3
- data/lib/protobuf/encoder.rb +0 -11
- data/lib/protobuf/enum.rb +0 -365
- data/lib/protobuf/exceptions.rb +0 -9
- data/lib/protobuf/field/base_field.rb +0 -380
- data/lib/protobuf/field/base_field_object_definitions.rb +0 -504
- data/lib/protobuf/field/bool_field.rb +0 -64
- data/lib/protobuf/field/bytes_field.rb +0 -67
- data/lib/protobuf/field/double_field.rb +0 -25
- data/lib/protobuf/field/enum_field.rb +0 -56
- data/lib/protobuf/field/field_array.rb +0 -102
- data/lib/protobuf/field/field_hash.rb +0 -122
- data/lib/protobuf/field/fixed32_field.rb +0 -25
- data/lib/protobuf/field/fixed64_field.rb +0 -28
- data/lib/protobuf/field/float_field.rb +0 -43
- data/lib/protobuf/field/int32_field.rb +0 -21
- data/lib/protobuf/field/int64_field.rb +0 -34
- data/lib/protobuf/field/integer_field.rb +0 -23
- data/lib/protobuf/field/message_field.rb +0 -51
- data/lib/protobuf/field/sfixed32_field.rb +0 -27
- data/lib/protobuf/field/sfixed64_field.rb +0 -28
- data/lib/protobuf/field/signed_integer_field.rb +0 -29
- data/lib/protobuf/field/sint32_field.rb +0 -21
- data/lib/protobuf/field/sint64_field.rb +0 -21
- data/lib/protobuf/field/string_field.rb +0 -51
- data/lib/protobuf/field/uint32_field.rb +0 -21
- data/lib/protobuf/field/uint64_field.rb +0 -21
- data/lib/protobuf/field/varint_field.rb +0 -77
- data/lib/protobuf/field.rb +0 -74
- data/lib/protobuf/generators/base.rb +0 -85
- data/lib/protobuf/generators/enum_generator.rb +0 -39
- data/lib/protobuf/generators/extension_generator.rb +0 -27
- data/lib/protobuf/generators/field_generator.rb +0 -193
- data/lib/protobuf/generators/file_generator.rb +0 -262
- data/lib/protobuf/generators/group_generator.rb +0 -122
- data/lib/protobuf/generators/message_generator.rb +0 -104
- data/lib/protobuf/generators/option_generator.rb +0 -17
- data/lib/protobuf/generators/printable.rb +0 -160
- data/lib/protobuf/generators/service_generator.rb +0 -50
- data/lib/protobuf/lifecycle.rb +0 -33
- data/lib/protobuf/logging.rb +0 -39
- data/lib/protobuf/message/fields.rb +0 -233
- data/lib/protobuf/message/serialization.rb +0 -85
- data/lib/protobuf/message.rb +0 -241
- data/lib/protobuf/optionable.rb +0 -72
- data/lib/protobuf/tasks/compile.rake +0 -80
- data/lib/protobuf/tasks.rb +0 -1
- data/lib/protobuf/varint.rb +0 -20
- data/lib/protobuf/varint_pure.rb +0 -31
- data/lib/protobuf/version.rb +0 -3
- data/lib/protobuf/wire_type.rb +0 -10
- data/lib/protobuf.rb +0 -91
- data/proto/dynamic_discovery.proto +0 -46
- data/proto/google/protobuf/compiler/plugin.proto +0 -183
- data/proto/google/protobuf/descriptor.proto +0 -911
- data/proto/rpc.proto +0 -71
- data/service_executables/.gitkeep +0 -0
- data/service_executables/VERSION +0 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c32847e196cdcf1540bd39373f9327a46e50cb1c4be6516f2ad5664696c0221
|
4
|
+
data.tar.gz: 03b9bc37cf6b8fe3fd0662f120f6f24cc9faf868cf91c7fb698ccbcb52f15aac
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 204a13ebf2cc20d9302d55a1d2201cc0f8f2ba35b5bf1b3392f75c0636f8ab5224de54106af8349c16da111d86f2381e894d8925eccf2df1e46e4d04b99eb7be
|
7
|
+
data.tar.gz: ac50424a98754b82bab6576b7205cdb3f6243f5dc6aa9c55f817f15cfba61e1f0858c27a66efd18457442f0b4f2e8ea42cdfcbecdd67c6941edcd86c77b11164
|
data/.gitignore
CHANGED
data/.simplecov
CHANGED
data/Rakefile
CHANGED
@@ -31,15 +31,46 @@ static VALUE contrast_assess_array_join(const int argc, const VALUE *argv,
|
|
31
31
|
return result;
|
32
32
|
}
|
33
33
|
|
34
|
+
static VALUE contrast_assess_prepend_array_join(const int argc, const VALUE *argv,
|
35
|
+
const VALUE ary) {
|
36
|
+
VALUE sep, result;
|
37
|
+
/* We need to figure out the separator the join method actually used. */
|
38
|
+
/* First, check if one was provided. */
|
39
|
+
rb_scan_args(argc, argv, "01", &sep);
|
40
|
+
/* Second, check to see if `$;` is set*/
|
41
|
+
if (NIL_P(sep)) {
|
42
|
+
sep = rb_output_fs;
|
43
|
+
}
|
44
|
+
|
45
|
+
/* call the Array.join but patched one */
|
46
|
+
result = rb_ary_join(ary, sep);
|
47
|
+
/* call the Contrast::Extensions::Assess::ArrayPropagator#cs__track_join */
|
48
|
+
result = rb_funcall(array_propagator, rb_sym_assess_track_array_join, 3,
|
49
|
+
ary, sep, result);
|
50
|
+
|
51
|
+
/*call original occurs in ruby*/
|
52
|
+
return Qtrue;
|
53
|
+
}
|
54
|
+
|
34
55
|
void Init_cs__assess_array(void) {
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
56
|
+
|
57
|
+
VALUE rb_mod_ary = rb_const_get(rb_cObject, rb_intern("Array"));
|
58
|
+
VALUE rb_sym_ary_join = ID2SYM(rb_intern("join"));
|
59
|
+
// check if prepended
|
60
|
+
VALUE is_prepended = contrast_check_prepended(rb_mod_ary, rb_sym_ary_join, Qtrue);
|
61
|
+
// register the cs__track_join method of the Array propagator, and call it here from Ruby.
|
62
|
+
array_propagator = rb_define_class_under(core_assess, "ArrayPropagator", rb_cObject);
|
63
|
+
rb_sym_assess_track_array_join = rb_intern("cs__track_join");
|
64
|
+
|
65
|
+
// register the cs__join method of the ContrastArray for prepending, and call it here from Ruby.
|
66
|
+
VALUE contrast_array = rb_define_module_under(core_assess, "ContrastArray");
|
67
|
+
rb_define_module_function(contrast_array, "cs__join", contrast_assess_prepend_array_join, -1);
|
68
|
+
|
69
|
+
if(is_prepended == Qtrue) {
|
70
|
+
// do nothing prepend is done in Ruby
|
71
|
+
} else {
|
72
|
+
// register alias patch
|
73
|
+
rb_sym_assess_array_join =
|
74
|
+
contrast_register_patch("Array", "join", contrast_assess_array_join);
|
75
|
+
}
|
45
76
|
}
|
@@ -3,8 +3,11 @@
|
|
3
3
|
static VALUE array_propagator;
|
4
4
|
static VALUE rb_sym_assess_array_join;
|
5
5
|
static VALUE rb_sym_assess_track_array_join;
|
6
|
-
|
6
|
+
static VALUE rb_mod_ary, rb_sym_ary_join, is_prepended, contrast_array;
|
7
7
|
static VALUE contrast_assess_array_join(const int argc, const VALUE *argv,
|
8
8
|
const VALUE ary);
|
9
9
|
|
10
|
+
static VALUE contrast_assess_prepend_array_join(const int argc, const VALUE *argv,
|
11
|
+
const VALUE ary);
|
12
|
+
|
10
13
|
void Init_cs__assess_array(void);
|
@@ -23,7 +23,7 @@ module Contrast
|
|
23
23
|
# A trigger method is one which can perform a dangerous action, as described by the
|
24
24
|
# Contrast::Agent::Assess::Policy::TriggerNode class. Each such method will call to this module just after
|
25
25
|
# invocation in order to determine if the call was done safely. In those cases where it was not, a Finding
|
26
|
-
# report is issued to
|
26
|
+
# report is issued to TeamServer.
|
27
27
|
module TriggerMethod
|
28
28
|
extend Contrast::Components::Logger::InstanceMethods
|
29
29
|
extend Contrast::Utils::Assess::TriggerMethodUtils
|
@@ -105,7 +105,7 @@ module Contrast
|
|
105
105
|
nil
|
106
106
|
end
|
107
107
|
|
108
|
-
# Given a finding, append it to an activity message and send it to the
|
108
|
+
# Given a finding, append it to an activity message and send it to the TeamServer for processing. If an
|
109
109
|
# activity message does not exist, b/c we're invoked outside of a request context, build an activity and
|
110
110
|
# immediately report it with the finding.
|
111
111
|
#
|
@@ -7,7 +7,7 @@ module Contrast
|
|
7
7
|
module Policy
|
8
8
|
module TriggerValidation
|
9
9
|
# Validator used to assert a REDOS finding is actually vulnerable
|
10
|
-
# before serializing that finding as a DTM to report to the
|
10
|
+
# before serializing that finding as a DTM to report to the TeamServer.
|
11
11
|
module REDOSValidator
|
12
12
|
RULE_NAME = 'redos'
|
13
13
|
|
@@ -7,7 +7,7 @@ module Contrast
|
|
7
7
|
module Policy
|
8
8
|
module TriggerValidation
|
9
9
|
# Validator used to assert a SSRF finding is actually vulnerable
|
10
|
-
# before serializing that finding as a DTM to report to the
|
10
|
+
# before serializing that finding as a DTM to report to the TeamServer.
|
11
11
|
module SSRFValidator
|
12
12
|
RULE_NAME = 'ssrf'
|
13
13
|
URL_PATTERN = %r{(?<protocol>http|https|ftp|sftp|telnet|gopher|rtsp|rtsps|ssh|svn)://(?<host>[^/?]+)(?<path>/?[^?]*)(?<query_string>\?.*)?}i.cs__freeze # rubocop:disable Layout/LineLength
|
@@ -8,7 +8,7 @@ module Contrast
|
|
8
8
|
module TriggerValidation
|
9
9
|
# Validator used to assert a Reflected XSS finding is actually
|
10
10
|
# vulnerable before serializing that finding as a DTM to report to
|
11
|
-
# the
|
11
|
+
# the TeamServer.
|
12
12
|
module XSSValidator
|
13
13
|
RULE_NAME = 'reflected-xss'
|
14
14
|
SAFE_CONTENT_TYPES = %w[/csv /javascript /json /pdf /x-javascript /x-json].cs__freeze
|
@@ -1,13 +1,17 @@
|
|
1
1
|
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
|
+
require 'contrast/agent/reporting/settings/url_exclusion'
|
5
|
+
|
4
6
|
module Contrast
|
5
7
|
module Agent
|
6
8
|
# Given an array of exclusion matcher instances provides methods to
|
7
9
|
# determine if the exclusions apply to particular urls.
|
8
10
|
class Excluder # rubocop:disable Metrics/ClassLength
|
11
|
+
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
9
12
|
attr_reader :exclusions
|
10
13
|
|
14
|
+
# @param exclusions [Array<Contrast::Agent::ExclusionMatcher>]
|
11
15
|
def initialize exclusions = []
|
12
16
|
@exclusions = exclusions
|
13
17
|
end
|
@@ -16,12 +20,12 @@ module Contrast
|
|
16
20
|
# then we can avoid any tracking for the request.
|
17
21
|
#
|
18
22
|
# @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
|
19
|
-
# return [Boolean]
|
23
|
+
# @return [Boolean]
|
20
24
|
def assess_excluded_by_url? request
|
21
25
|
request_path = request.path
|
22
26
|
|
23
|
-
assess_url_exclusions_for_all_rules.any? do |
|
24
|
-
path_match?(
|
27
|
+
assess_url_exclusions_for_all_rules.any? do |exclusion_matcher|
|
28
|
+
path_match?(exclusion_matcher, request_path)
|
25
29
|
end
|
26
30
|
end
|
27
31
|
|
@@ -34,9 +38,9 @@ module Contrast
|
|
34
38
|
def assess_excluded_by_url_and_rule? request, rule_id
|
35
39
|
request_path = request.path
|
36
40
|
|
37
|
-
assess_url_exclusions.any? do |
|
38
|
-
path_match?(
|
39
|
-
(
|
41
|
+
assess_url_exclusions.any? do |exclusion_matcher|
|
42
|
+
path_match?(exclusion_matcher, request_path) &&
|
43
|
+
(exclusion_matcher.assess_rules.empty? || exclusion_matcher.assess_rules.include?(rule_id))
|
40
44
|
end
|
41
45
|
end
|
42
46
|
|
@@ -44,13 +48,14 @@ module Contrast
|
|
44
48
|
# rules, then we can avoid tracking this entry.
|
45
49
|
#
|
46
50
|
# @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
|
47
|
-
# @param
|
51
|
+
# @param source_type [String]
|
52
|
+
# @param source_name [String]
|
48
53
|
# return [Boolean]
|
49
54
|
def assess_excluded_by_input? request, source_type, source_name
|
50
55
|
request_path = request.path
|
51
56
|
|
52
|
-
assess_input_exclusions_for_all_rules.any? do |
|
53
|
-
input_match?(
|
57
|
+
assess_input_exclusions_for_all_rules.any? do |exclusion_matcher|
|
58
|
+
input_match?(exclusion_matcher, source_type, source_name) && path_match?(exclusion_matcher, request_path)
|
54
59
|
end
|
55
60
|
end
|
56
61
|
|
@@ -66,11 +71,11 @@ module Contrast
|
|
66
71
|
|
67
72
|
# We need to check for url exclusions here for the input rules as the url exclusions
|
68
73
|
# that have already been checked didn't include the INPUT exclusions. So we look for
|
69
|
-
# any INPUT exclusions that apply to the current url and the
|
74
|
+
# any INPUT exclusions that apply to the current url and the supplied rule.
|
70
75
|
path = request.path
|
71
|
-
rule_input_exclusions = assess_input_exclusions.select do |
|
72
|
-
(
|
73
|
-
|
76
|
+
rule_input_exclusions = assess_input_exclusions.select do |exclusion_matcher|
|
77
|
+
(exclusion_matcher.protection_rules.empty? || exclusion_matcher.protection_rules.include?(rule)) &&
|
78
|
+
path_match?(exclusion_matcher, path)
|
74
79
|
end
|
75
80
|
return false if rule_input_exclusions.empty?
|
76
81
|
|
@@ -94,72 +99,85 @@ module Contrast
|
|
94
99
|
def protect_excluded_by_url? request
|
95
100
|
request_path = request.path
|
96
101
|
|
97
|
-
protect_url_exclusions_for_all_rules.any? do |
|
98
|
-
path_match?(
|
102
|
+
protect_url_exclusions_for_all_rules.any? do |exclusion_matcher|
|
103
|
+
path_match?(exclusion_matcher, request_path)
|
99
104
|
end
|
100
105
|
end
|
101
106
|
|
102
107
|
private
|
103
108
|
|
109
|
+
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
104
110
|
def assess_url_exclusions_for_all_rules
|
105
|
-
@_assess_url_exclusions_for_all_rules ||= assess_url_exclusions.select do |
|
106
|
-
|
111
|
+
@_assess_url_exclusions_for_all_rules ||= assess_url_exclusions.select do |exclusion_matcher|
|
112
|
+
exclusion_matcher.assess_rules.empty?
|
107
113
|
end
|
108
114
|
end
|
109
115
|
|
116
|
+
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
110
117
|
def assess_url_exclusions
|
111
|
-
@_assess_url_exclusions ||= assess_exclusions.select do |
|
112
|
-
|
118
|
+
@_assess_url_exclusions ||= assess_exclusions.select do |exclusion_matcher|
|
119
|
+
exclusion_matcher.type == :URL
|
113
120
|
end
|
114
121
|
end
|
115
122
|
|
123
|
+
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
116
124
|
def assess_input_exclusions_for_all_rules
|
117
|
-
@_assess_input_exclusions_for_all_rules ||= assess_input_exclusions.select do |
|
118
|
-
|
125
|
+
@_assess_input_exclusions_for_all_rules ||= assess_input_exclusions.select do |exclusion_matcher|
|
126
|
+
exclusion_matcher.assess_rules.empty?
|
119
127
|
end
|
120
128
|
end
|
121
129
|
|
130
|
+
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
122
131
|
def assess_input_exclusions
|
123
|
-
@_assess_input_exclusions ||= assess_exclusions.select do |
|
124
|
-
|
132
|
+
@_assess_input_exclusions ||= assess_exclusions.select do |exclusion_matcher|
|
133
|
+
exclusion_matcher.type == :INPUT
|
125
134
|
end
|
126
135
|
end
|
127
136
|
|
137
|
+
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
128
138
|
def assess_exclusions
|
129
139
|
@_assess_exclusions ||= @exclusions.select(&:assess)
|
130
140
|
end
|
131
141
|
|
142
|
+
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
132
143
|
def protect_url_exclusions_for_all_rules
|
133
|
-
@_protect_url_exclusions_for_all_rules ||= protect_url_exclusions.select do |
|
134
|
-
|
144
|
+
@_protect_url_exclusions_for_all_rules ||= protect_url_exclusions.select do |exclusion_matcher|
|
145
|
+
exclusion_matcher.protect_rules.empty?
|
135
146
|
end
|
136
147
|
end
|
137
148
|
|
149
|
+
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
138
150
|
def protect_url_exclusions
|
139
|
-
@_protect_url_exclusions ||= protect_exclusions.select do |
|
140
|
-
|
151
|
+
@_protect_url_exclusions ||= protect_exclusions.select do |exclusion_matcher|
|
152
|
+
exclusion_matcher.type == :URL
|
141
153
|
end
|
142
154
|
end
|
143
155
|
|
156
|
+
# @return [Array<Contrast::Agent::ExclusionMatcher>]
|
144
157
|
def protect_exclusions
|
145
158
|
@_protect_exclusions ||= @exclusions.select(&:protect)
|
146
159
|
end
|
147
160
|
|
148
|
-
|
149
|
-
|
161
|
+
# @return [Boolean]
|
162
|
+
def path_match? exclusion_matcher, path
|
163
|
+
exclusion_matcher.wildcard_url || exclusion_matcher.urls.any? { |url| url.match?(path) }
|
150
164
|
end
|
151
165
|
|
166
|
+
# @param exclusion [Contrast::Agent::ExclusionMatcher]
|
167
|
+
# @param source_type [String]
|
168
|
+
# @param source_name [String]
|
169
|
+
# @return [Boolean]
|
152
170
|
def input_match? exclusion, source_type, source_name
|
153
171
|
case exclusion.input_type
|
154
|
-
when
|
172
|
+
when 'PARAMETER'
|
155
173
|
input_match_parameter?(exclusion, source_type, source_name)
|
156
|
-
when
|
174
|
+
when 'COOKIE'
|
157
175
|
input_match_cookie?(exclusion, source_type, source_name)
|
158
|
-
when
|
176
|
+
when 'HEADER'
|
159
177
|
input_match_header?(exclusion, source_type, source_name)
|
160
|
-
when
|
178
|
+
when 'BODY'
|
161
179
|
Contrast::Agent::Assess::Policy::SourceMethod::BODY_TYPE == source_type
|
162
|
-
when
|
180
|
+
when 'QUERYSTRING'
|
163
181
|
Contrast::Agent::Assess::Policy::SourceMethod::QUERYSTRING_TYPE == source_type
|
164
182
|
else
|
165
183
|
false
|
@@ -2,6 +2,10 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'contrast/components/logger'
|
5
|
+
require 'contrast/agent/reporting/settings/exclusion_base'
|
6
|
+
require 'contrast/agent/reporting/settings/code_exclusion'
|
7
|
+
require 'contrast/agent/reporting/settings/input_exclusion'
|
8
|
+
require 'contrast/agent/reporting/settings/url_exclusion'
|
5
9
|
|
6
10
|
module Contrast
|
7
11
|
module Agent
|
@@ -13,22 +17,30 @@ module Contrast
|
|
13
17
|
|
14
18
|
extend Forwardable
|
15
19
|
|
16
|
-
attr_reader :protect, :assess, :urls, :wildcard_url, :wildcard_input
|
20
|
+
attr_reader :protect, :assess, :type, :urls, :wildcard_url, :wildcard_input
|
17
21
|
|
18
|
-
def_delegators :@exclusion, :
|
22
|
+
def_delegators :@exclusion, :protect_rules, :assess_rules, :input_type, :input_name
|
19
23
|
|
20
24
|
# Create a matcher around an exclusion sent from TeamServer.
|
21
25
|
#
|
22
|
-
# @param excl [Contrast::
|
26
|
+
# @param excl [Contrast::Agent::Reporting::Settings::ExclusionBase]
|
23
27
|
# @return [Contrast::Agent::ExclusionMatcher]
|
24
28
|
def initialize excl
|
25
29
|
@exclusion = excl
|
26
30
|
@protect = @exclusion.protect
|
27
31
|
@assess = @exclusion.assess
|
28
32
|
|
29
|
-
|
30
|
-
|
31
|
-
|
33
|
+
case excl
|
34
|
+
when Contrast::Agent::Reporting::Settings::CodeExclusion
|
35
|
+
handle_wildcard_code
|
36
|
+
@type = :CODE
|
37
|
+
when Contrast::Agent::Reporting::Settings::InputExclusion
|
38
|
+
handle_wildcard_input
|
39
|
+
@type = :INPUT
|
40
|
+
when Contrast::Agent::Reporting::Settings::UrlExclusion
|
41
|
+
handle_wildcard_url
|
42
|
+
@type = :URL
|
43
|
+
end
|
32
44
|
end
|
33
45
|
|
34
46
|
# According to the docs for exclusions, user input applies to all inputs if
|
@@ -97,7 +109,7 @@ module Contrast
|
|
97
109
|
end
|
98
110
|
|
99
111
|
def code?
|
100
|
-
@
|
112
|
+
@type == :CODE
|
101
113
|
end
|
102
114
|
|
103
115
|
def match_all?
|
@@ -105,12 +117,12 @@ module Contrast
|
|
105
117
|
end
|
106
118
|
|
107
119
|
# Determine if the given rule is excluded by this exclusion.
|
108
|
-
# In this case, the `
|
120
|
+
# In this case, the `protect_rules` being empty means apply to all rules,
|
109
121
|
# not no rules
|
110
122
|
#
|
111
123
|
# @param rule - the id of the rule which we're checking for exclusion
|
112
124
|
def protection_rule? rule
|
113
|
-
protect? && (@exclusion.
|
125
|
+
protect? && (@exclusion.protect_rules.empty? || @exclusion.protect_rules.include?(rule))
|
114
126
|
end
|
115
127
|
|
116
128
|
# Determine if the given rule is excluded by this exclusion.
|
@@ -73,12 +73,12 @@ module Contrast
|
|
73
73
|
private
|
74
74
|
|
75
75
|
# Startup the Agent as part of the initialization process:
|
76
|
-
# - start the
|
77
|
-
# - start the heartbeat thread, which
|
76
|
+
# - start the TeamServer sending thread, responsible for sending and processing messages
|
77
|
+
# - start the heartbeat thread, which handles periodic messages to TeamServer
|
78
78
|
# - start instrumenting libraries and do a 'catchup' patch for everything we didn't see get loaded
|
79
79
|
# - enable TracePoint, which handles all class loads and required instrumentation going forward
|
80
80
|
def agent_startup_routine
|
81
|
-
logger.debug_with_time('middleware: starting
|
81
|
+
logger.debug_with_time('middleware: starting reporting threads') do
|
82
82
|
Contrast::Agent.thread_watcher.ensure_running?
|
83
83
|
end
|
84
84
|
|
@@ -147,7 +147,7 @@ module Contrast
|
|
147
147
|
# which is being triggered when there is a failure within the pre-call with the agent
|
148
148
|
def pre_call_with_agent context, request_handler
|
149
149
|
with_contrast_scope do
|
150
|
-
context.
|
150
|
+
context.protect_input_analysis
|
151
151
|
request_handler.ruleset.prefilter
|
152
152
|
end
|
153
153
|
rescue StandardError => e
|
@@ -56,6 +56,7 @@ module Contrast
|
|
56
56
|
unless Contrast::Agent::Assess.cs__object_method_prepended?(Marshal, :load, false)
|
57
57
|
apply_marshal_load_alias_patch
|
58
58
|
end
|
59
|
+
apply_array_join_prepend_patch if Contrast::Agent::Assess.cs__object_method_prepended?(Array, :join, true)
|
59
60
|
true
|
60
61
|
end
|
61
62
|
end
|
@@ -121,6 +122,11 @@ module Contrast
|
|
121
122
|
Marshal.alias_method(:cs__marshal_load, :load)
|
122
123
|
Marshal.alias_method(:load, :cs__marshal_load)
|
123
124
|
end
|
125
|
+
|
126
|
+
# Prepend Contrast::Extension::Assess::ContrastArray to pick up the ContrastArray#join method
|
127
|
+
def apply_array_join_prepend_patch
|
128
|
+
Array.prepend(Contrast::Extension::Assess::ContrastArray)
|
129
|
+
end
|
124
130
|
end
|
125
131
|
end
|
126
132
|
end
|