contrast-agent 6.7.0 → 6.8.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/.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
|