contrast-agent 5.1.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/cs__assess_kernel/cs__assess_kernel.c +7 -4
- data/ext/cs__assess_module/cs__assess_module.c +7 -7
- data/ext/cs__common/cs__common.c +4 -0
- data/ext/cs__common/cs__common.h +1 -0
- data/ext/cs__contrast_patch/cs__contrast_patch.c +52 -27
- data/ext/cs__contrast_patch/cs__contrast_patch.h +2 -0
- data/ext/cs__scope/cs__scope.c +747 -0
- data/ext/cs__scope/cs__scope.h +88 -0
- data/ext/cs__scope/extconf.rb +5 -0
- data/lib/contrast/agent/assess/contrast_event.rb +20 -13
- data/lib/contrast/agent/assess/contrast_object.rb +4 -1
- data/lib/contrast/agent/assess/policy/propagation_node.rb +2 -5
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +2 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +4 -1
- data/lib/contrast/agent/assess/rule/response/{autocomplete_rule.rb → auto_complete_rule.rb} +4 -3
- data/lib/contrast/agent/assess/rule/response/base_rule.rb +12 -79
- data/lib/contrast/agent/assess/rule/response/body_rule.rb +109 -0
- data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +157 -0
- data/lib/contrast/agent/assess/rule/response/click_jacking_header_rule.rb +26 -0
- data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +14 -15
- data/lib/contrast/agent/assess/rule/response/csp_header_missing_rule.rb +5 -25
- data/lib/contrast/agent/assess/rule/response/framework/rails_support.rb +29 -0
- data/lib/contrast/agent/assess/rule/response/header_rule.rb +70 -0
- data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +12 -36
- data/lib/contrast/agent/assess/rule/response/parameters_pollution_rule.rb +2 -1
- data/lib/contrast/agent/assess/rule/response/x_content_type_header_rule.rb +26 -0
- data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +36 -0
- data/lib/contrast/agent/middleware.rb +1 -0
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +1 -3
- data/lib/contrast/agent/patching/policy/patch.rb +2 -6
- data/lib/contrast/agent/patching/policy/patcher.rb +1 -1
- data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +94 -0
- data/lib/contrast/agent/protect/rule/base.rb +28 -1
- data/lib/contrast/agent/protect/rule/base_service.rb +10 -1
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +2 -0
- data/lib/contrast/agent/protect/rule/deserialization.rb +6 -0
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +5 -1
- data/lib/contrast/agent/protect/rule/no_sqli.rb +1 -0
- data/lib/contrast/agent/protect/rule/path_traversal.rb +1 -0
- data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +124 -0
- data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +121 -0
- data/lib/contrast/agent/protect/rule/sqli.rb +33 -0
- data/lib/contrast/agent/protect/rule/xxe.rb +4 -0
- data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +44 -0
- data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +115 -0
- data/lib/contrast/agent/reporting/input_analysis/input_type.rb +44 -0
- data/lib/contrast/agent/reporting/input_analysis/score_level.rb +21 -0
- data/lib/contrast/agent/reporting/report.rb +1 -0
- data/lib/contrast/agent/reporting/reporter.rb +8 -1
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +69 -36
- data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +88 -59
- data/lib/contrast/agent/reporting/reporting_events/{finding_object.rb → finding_event_object.rb} +24 -20
- data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +39 -0
- data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +40 -0
- data/lib/contrast/agent/reporting/reporting_events/{finding_signature.rb → finding_event_signature.rb} +29 -24
- data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +12 -8
- data/lib/contrast/agent/reporting/reporting_events/{finding_stack.rb → finding_event_stack.rb} +23 -19
- data/lib/contrast/agent/reporting/reporting_events/{finding_taint_range.rb → finding_event_taint_range.rb} +17 -15
- data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +26 -53
- data/lib/contrast/agent/reporting/reporting_events/poll.rb +29 -0
- data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +5 -4
- data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +1 -0
- data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +10 -3
- data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +0 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -0
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +28 -20
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +13 -1
- data/lib/contrast/agent/request_context.rb +6 -1
- data/lib/contrast/agent/request_context_extend.rb +85 -21
- data/lib/contrast/agent/scope.rb +102 -107
- data/lib/contrast/agent/service_heartbeat.rb +45 -2
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/decorators/bot_blocker.rb +37 -0
- data/lib/contrast/api/decorators/ip_denylist.rb +37 -0
- data/lib/contrast/api/decorators/rasp_rule_sample.rb +29 -0
- data/lib/contrast/api/decorators/user_input.rb +11 -1
- data/lib/contrast/api/decorators/virtual_patch.rb +34 -0
- data/lib/contrast/components/logger.rb +5 -0
- data/lib/contrast/components/protect.rb +4 -2
- data/lib/contrast/components/scope.rb +98 -91
- data/lib/contrast/config/agent_configuration.rb +58 -12
- data/lib/contrast/config/api_configuration.rb +100 -12
- data/lib/contrast/config/api_proxy_configuration.rb +55 -3
- data/lib/contrast/config/application_configuration.rb +114 -15
- data/lib/contrast/config/assess_configuration.rb +106 -12
- data/lib/contrast/config/assess_rules_configuration.rb +44 -3
- data/lib/contrast/config/base_configuration.rb +1 -0
- data/lib/contrast/config/certification_configuration.rb +74 -3
- data/lib/contrast/config/exception_configuration.rb +61 -3
- data/lib/contrast/config/heap_dump_configuration.rb +101 -17
- data/lib/contrast/config/inventory_configuration.rb +64 -3
- data/lib/contrast/config/logger_configuration.rb +46 -3
- data/lib/contrast/config/protect_rule_configuration.rb +36 -9
- data/lib/contrast/config/protect_rules_configuration.rb +120 -17
- data/lib/contrast/config/request_audit_configuration.rb +68 -3
- data/lib/contrast/config/ruby_configuration.rb +96 -22
- data/lib/contrast/config/sampling_configuration.rb +76 -10
- data/lib/contrast/config/server_configuration.rb +56 -11
- data/lib/contrast/configuration.rb +6 -3
- data/lib/contrast/logger/cef_log.rb +151 -0
- data/lib/contrast/utils/hash_digest.rb +14 -6
- data/lib/contrast/utils/log_utils.rb +114 -0
- data/lib/contrast/utils/middleware_utils.rb +6 -7
- data/lib/contrast/utils/net_http_base.rb +12 -9
- data/lib/contrast/utils/patching/policy/patch_utils.rb +0 -4
- data/lib/contrast.rb +4 -3
- data/ruby-agent.gemspec +1 -1
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +41 -21
- data/lib/contrast/agent/assess/rule/response/cachecontrol_rule.rb +0 -184
- data/lib/contrast/agent/assess/rule/response/clickjacking_rule.rb +0 -66
- data/lib/contrast/agent/assess/rule/response/x_content_type_rule.rb +0 -52
- data/lib/contrast/agent/assess/rule/response/x_xss_protection_rule.rb +0 -53
- data/lib/contrast/extension/kernel.rb +0 -54
|
@@ -6,31 +6,36 @@ require 'contrast/utils/object_share'
|
|
|
6
6
|
module Contrast
|
|
7
7
|
module Agent
|
|
8
8
|
module Reporting
|
|
9
|
-
# This is the new
|
|
10
|
-
# system to relay this information in the Finding/Trace messages. These
|
|
11
|
-
# construct the
|
|
12
|
-
# was
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
attr_reader :
|
|
29
|
-
|
|
9
|
+
# This is the new FindingEventSignature class which will include all the needed information for the new reporting
|
|
10
|
+
# system to relay this information in the Finding/Trace messages. These FindingEventSignatures are used by
|
|
11
|
+
# TeamServer to construct the method signature for the assess feature. They represent the method invoked when the
|
|
12
|
+
# FindingEvent was generated.
|
|
13
|
+
class FindingEventSignature
|
|
14
|
+
# @return [String] the types of the arguments in this event; may be different for each invocation of the
|
|
15
|
+
# method.
|
|
16
|
+
attr_reader :arg_types
|
|
17
|
+
# @return [String] the name of the class of this object or the name itself if of Module type.
|
|
18
|
+
attr_reader :class_name
|
|
19
|
+
# @return [Boolean] if the method is a constructor or not.
|
|
20
|
+
attr_reader :constructor
|
|
21
|
+
# @return [String] unused.
|
|
22
|
+
attr_reader :expression_type
|
|
23
|
+
# @return [Integer] the Java flags; static or not.
|
|
24
|
+
attr_reader :flags
|
|
25
|
+
# @return [String] the name of the method.
|
|
26
|
+
attr_reader :method_name
|
|
27
|
+
# @return [String] unused.
|
|
28
|
+
attr_reader :operator
|
|
29
|
+
# @return [String] the type of the return in this event; may be different for each invocation of the method.
|
|
30
|
+
attr_reader :return_type
|
|
31
|
+
# @return [String] unused.
|
|
32
|
+
attr_reader :signature
|
|
33
|
+
# @return [Boolean] if the method is void or not; may be different for each invocation of the method.
|
|
34
|
+
attr_reader :void_method
|
|
30
35
|
|
|
31
36
|
class << self
|
|
32
37
|
# @param event [Contrast::Agent::Assess::ContrastEvent] the event to build a signature for
|
|
33
|
-
# @return [Contrast::Agent::Reporting::
|
|
38
|
+
# @return [Contrast::Agent::Reporting::FindingEventSignature]
|
|
34
39
|
def convert event
|
|
35
40
|
report = new
|
|
36
41
|
report.attach_data(event)
|
|
@@ -39,7 +44,7 @@ module Contrast
|
|
|
39
44
|
end
|
|
40
45
|
|
|
41
46
|
# Parse the data from a Contrast::Agent::Assess::ContrastEvent to attach what is required for reporting to
|
|
42
|
-
# TeamServer to this Contrast::Agent::Reporting::
|
|
47
|
+
# TeamServer to this Contrast::Agent::Reporting::FindingEventSignature
|
|
43
48
|
#
|
|
44
49
|
# @param event [Contrast::Agent::Assess::ContrastEvent]
|
|
45
50
|
def attach_data event
|
|
@@ -52,7 +57,7 @@ module Contrast
|
|
|
52
57
|
@constructor = node.method_name == :new || node.method_name == :initialize
|
|
53
58
|
# 8 is STATIC in Java... we have to placate them for now it has been requested that flags be removed since it
|
|
54
59
|
# isn't used
|
|
55
|
-
@flags = 8 unless
|
|
60
|
+
@flags = 8 unless node.instance_method?
|
|
56
61
|
@method_name = node.method_name
|
|
57
62
|
@return_type = type_name(event.ret)
|
|
58
63
|
# if there's a ret, then this method isn't nil. not 100% full proof since you can return nil, but this is the
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require 'base64'
|
|
5
|
+
require 'contrast/agent/assess/contrast_event'
|
|
6
|
+
require 'contrast/agent/assess/events/source_event'
|
|
5
7
|
|
|
6
8
|
module Contrast
|
|
7
9
|
module Agent
|
|
@@ -10,16 +12,18 @@ module Contrast
|
|
|
10
12
|
# system to relay this information in the Finding/Trace messages. These FindingEventSource are used by TeamServer
|
|
11
13
|
# to construct the vulnerability information for the assess feature. They indicate the type of data that the
|
|
12
14
|
# event represents.
|
|
13
|
-
#
|
|
14
|
-
# @attr_reader name [String] the name of the source
|
|
15
|
-
# @attr_reader type [String] the type of the source
|
|
16
15
|
class FindingEventSource
|
|
17
|
-
|
|
16
|
+
# @return [String] the name of the source
|
|
17
|
+
attr_reader :name
|
|
18
|
+
# @return [String] the type of the source
|
|
19
|
+
attr_reader :type
|
|
18
20
|
|
|
19
21
|
class << self
|
|
20
|
-
# @param event [Contrast::Agent::Assess::Events::
|
|
21
|
-
# @return [Contrast::Agent::Reporting::
|
|
22
|
+
# @param event [Contrast::Agent::Assess::Events::ContrastEvent] the event to pull the source off of
|
|
23
|
+
# @return [Contrast::Agent::Reporting::FindingEventSource]
|
|
22
24
|
def convert event
|
|
25
|
+
return unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
|
|
26
|
+
|
|
23
27
|
report = new
|
|
24
28
|
report.attach_data(event)
|
|
25
29
|
report
|
|
@@ -43,8 +47,8 @@ module Contrast
|
|
|
43
47
|
def to_controlled_hash
|
|
44
48
|
validate
|
|
45
49
|
{
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
sourceName: name, # rubocop:disable Security/Module/Name
|
|
51
|
+
sourceType: type
|
|
48
52
|
}
|
|
49
53
|
end
|
|
50
54
|
|
data/lib/contrast/agent/reporting/reporting_events/{finding_stack.rb → finding_event_stack.rb}
RENAMED
|
@@ -4,25 +4,29 @@
|
|
|
4
4
|
module Contrast
|
|
5
5
|
module Agent
|
|
6
6
|
module Reporting
|
|
7
|
-
# This is the new
|
|
8
|
-
# to relay this information in the Finding/Trace messages. These
|
|
9
|
-
# the vulnerability information for the assess feature. They represent the callstack at the time
|
|
10
|
-
# FindingEvent was generated.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
attr_reader :
|
|
7
|
+
# This is the new FindingEventStack class which will include all the needed information for the new reporting
|
|
8
|
+
# system to relay this information in the Finding/Trace messages. These FindingEventStack are used by TeamServer
|
|
9
|
+
# to construct the vulnerability information for the assess feature. They represent the callstack at the time
|
|
10
|
+
# that each FindingEvent was generated.
|
|
11
|
+
class FindingEventStack
|
|
12
|
+
# @return [String] unused
|
|
13
|
+
attr_reader :eval
|
|
14
|
+
# @return [String] the stack frame to show in TeamServer; the value of an entry in #caller
|
|
15
|
+
attr_reader :file
|
|
16
|
+
# @return [String] unused
|
|
17
|
+
attr_reader :line_number
|
|
18
|
+
# @return [String] unused
|
|
19
|
+
attr_reader :method
|
|
20
|
+
# @return [String] unused
|
|
21
|
+
attr_reader :signature
|
|
22
|
+
# @return [String] unused
|
|
23
|
+
attr_reader :type
|
|
20
24
|
|
|
21
25
|
AGENT_CLASS_MARKER = '/lib/contrast/'
|
|
22
26
|
|
|
23
27
|
class << self
|
|
24
|
-
# @param stack [
|
|
25
|
-
# @return [Contrast::Agent::Reporting::
|
|
28
|
+
# @param stack [String]
|
|
29
|
+
# @return [Contrast::Agent::Reporting::FindingEventStack,nil]
|
|
26
30
|
def convert stack
|
|
27
31
|
return unless stack
|
|
28
32
|
return if stack.include?(AGENT_CLASS_MARKER)
|
|
@@ -34,9 +38,9 @@ module Contrast
|
|
|
34
38
|
end
|
|
35
39
|
|
|
36
40
|
# Parse the data from a Contrast::Agent::Assess::Tag to attach what is required for reporting to TeamServer to
|
|
37
|
-
# this Contrast::Agent::Reporting::
|
|
41
|
+
# this Contrast::Agent::Reporting::FindingEventTaintRange
|
|
38
42
|
#
|
|
39
|
-
# @param stack [
|
|
43
|
+
# @param stack [String]
|
|
40
44
|
def attach_data stack
|
|
41
45
|
@file = stack
|
|
42
46
|
end
|
|
@@ -49,8 +53,8 @@ module Contrast
|
|
|
49
53
|
def to_controlled_hash
|
|
50
54
|
validate
|
|
51
55
|
{
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
file: file
|
|
57
|
+
# eval: eval, # This is unused by the Ruby agent
|
|
54
58
|
# line_number: line_number, # This is unused by the Ruby agent
|
|
55
59
|
# method: method, # This is unused by the Ruby agent
|
|
56
60
|
# signature: signature, # This is unused by the Ruby agent
|
|
@@ -1,22 +1,24 @@
|
|
|
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/assess/tag'
|
|
5
|
+
|
|
4
6
|
module Contrast
|
|
5
7
|
module Agent
|
|
6
8
|
module Reporting
|
|
7
|
-
# This is the new
|
|
8
|
-
# to relay this information in the Finding/Trace messages. These FindingTaintRanges are used by
|
|
9
|
-
# construct the vulnerability information for the assess feature. They represent those parts of the
|
|
10
|
-
# are tracked because of a security relevant operation acting on them.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
attr_reader :
|
|
9
|
+
# This is the new FindingEventTaintRange class which will include all the needed information for the new
|
|
10
|
+
# reporting system to relay this information in the Finding/Trace messages. These FindingTaintRanges are used by
|
|
11
|
+
# TeamServer to construct the vulnerability information for the assess feature. They represent those parts of the
|
|
12
|
+
# objects that are tracked because of a security relevant operation acting on them.
|
|
13
|
+
class FindingEventTaintRange
|
|
14
|
+
# @return [String] the range (inclusive:exclusive), that this tag covers.
|
|
15
|
+
attr_reader :range
|
|
16
|
+
# @return [String] the type of action this tag represents.
|
|
17
|
+
attr_reader :tag
|
|
16
18
|
|
|
17
19
|
class << self
|
|
18
20
|
# @param tag [Contrast::Agent::Assess::Tag] the tag to convert
|
|
19
|
-
# @return [Contrast::Agent::Reporting::
|
|
21
|
+
# @return [Contrast::Agent::Reporting::FindingEventTaintRange]
|
|
20
22
|
def convert tag
|
|
21
23
|
report = new
|
|
22
24
|
report.attach_data(tag)
|
|
@@ -25,7 +27,7 @@ module Contrast
|
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
# Parse the data from a Contrast::Agent::Assess::Tag to attach what is required for reporting to TeamServer to
|
|
28
|
-
# this Contrast::Agent::Reporting::
|
|
30
|
+
# this Contrast::Agent::Reporting::FindingEventTaintRange
|
|
29
31
|
#
|
|
30
32
|
# @param tag [Contrast::Agent::Assess::Tag] the tag to convert
|
|
31
33
|
def attach_data tag
|
|
@@ -47,10 +49,10 @@ module Contrast
|
|
|
47
49
|
end
|
|
48
50
|
|
|
49
51
|
def validate
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
raise(ArgumentError, "#{ self } did not have a proper
|
|
52
|
+
unless range && !range.empty?
|
|
53
|
+
raise(ArgumentError, "#{ self } did not have a proper range. Unable to continue.")
|
|
54
|
+
end
|
|
55
|
+
raise(ArgumentError, "#{ self } did not have a proper tag. Unable to continue.") unless tag && !tag.empty?
|
|
54
56
|
end
|
|
55
57
|
end
|
|
56
58
|
end
|
|
@@ -4,31 +4,36 @@
|
|
|
4
4
|
module Contrast
|
|
5
5
|
module Agent
|
|
6
6
|
module Reporting
|
|
7
|
-
# This is the new
|
|
8
|
-
# relay this information in the Finding/Trace messages. These
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# @attr_accessor events [Array<Contrast::Agent::Assess::ContrastEvent>] if a dataflow based finding, the
|
|
13
|
-
# representation of those method calls which constitute a dangerous code path.
|
|
14
|
-
# @attr_accessor properties [Hash<String,String>] a set of values that TeamServer can use to provide more context
|
|
15
|
-
# to the user when rendering the finding. For some findings, a specific set of keys and values are required.
|
|
16
|
-
# @attr_accessor request [Contrast::Agent::Request, nil] the request, if any, in which this finding occurred
|
|
17
|
-
# @attr_accessor hash_code [String] the unique identifier of this finding.
|
|
18
|
-
# @attr_reader rule_id [String] the name of the rule violated; must match those in TeamServer.
|
|
7
|
+
# This is the new FindingRequest class which will include all the needed information for the new reporting system
|
|
8
|
+
# to relay this information in the Finding/Trace messages. These requests are used by TeamServer to construct the
|
|
9
|
+
# HTTP information for the assess feature. They represent the literal request made that resulted in the
|
|
10
|
+
# vulnerability being triggered.
|
|
19
11
|
class FindingRequest
|
|
20
|
-
|
|
12
|
+
# @return [String] the body of this request
|
|
13
|
+
attr_reader :body
|
|
14
|
+
# @return [Hash<String,Array<String>>] the headers of this request
|
|
15
|
+
attr_reader :headers
|
|
16
|
+
# @return [String] the HTTP verb of this request
|
|
17
|
+
attr_reader :method
|
|
18
|
+
# @return [Hash<String,Array<String>>] the parameters of this request
|
|
19
|
+
attr_reader :parameters
|
|
20
|
+
# @return [Integer] the port to which this request connected
|
|
21
|
+
attr_reader :port
|
|
22
|
+
# @return [String] the HTTP(S) protocol of this request
|
|
23
|
+
attr_reader :protocol
|
|
24
|
+
# @return [String] the query string of this request
|
|
25
|
+
attr_reader :query_string
|
|
26
|
+
# @return [String] the url, including path and script, of this request
|
|
27
|
+
attr_reader :uri
|
|
28
|
+
# @return [String] the HTTP version of this request
|
|
29
|
+
attr_reader :version
|
|
21
30
|
|
|
22
31
|
class << self
|
|
23
|
-
# @param request [Contrast::
|
|
32
|
+
# @param request [Contrast::Agent::Request]
|
|
24
33
|
# @return [Contrast::Agent::Reporting::FindingRequest]
|
|
25
34
|
def convert request
|
|
26
35
|
report = new
|
|
27
|
-
|
|
28
|
-
report.attach_data(request)
|
|
29
|
-
else
|
|
30
|
-
report.attach_dtm_data(request)
|
|
31
|
-
end
|
|
36
|
+
report.attach_data(request)
|
|
32
37
|
report
|
|
33
38
|
end
|
|
34
39
|
end
|
|
@@ -41,8 +46,6 @@ module Contrast
|
|
|
41
46
|
@body = request.body
|
|
42
47
|
@headers = {}
|
|
43
48
|
request.headers.each_pair do |key, value|
|
|
44
|
-
next unless key && value
|
|
45
|
-
|
|
46
49
|
# We need to change from the uppercase _ format to capitalized - format.
|
|
47
50
|
header = key.split('_')
|
|
48
51
|
header.each(&:capitalize!)
|
|
@@ -51,9 +54,7 @@ module Contrast
|
|
|
51
54
|
end
|
|
52
55
|
@method = request.request_method
|
|
53
56
|
@parameters = {}
|
|
54
|
-
request.parameters.each_pair
|
|
55
|
-
@parameters[key] = value
|
|
56
|
-
end
|
|
57
|
+
request.parameters.each_pair { |key, value| @parameters[key] = Array(value) }
|
|
57
58
|
@port = request.port || 0
|
|
58
59
|
@protocol = request.scheme
|
|
59
60
|
@query_string = request.query_string
|
|
@@ -61,34 +62,6 @@ module Contrast
|
|
|
61
62
|
@version = request.version
|
|
62
63
|
end
|
|
63
64
|
|
|
64
|
-
# Parse the data from a Contrast::Api::Dtm::HttpRequest to attach what is required for reporting to TeamServer
|
|
65
|
-
# to this Contrast::Agent::Reporting::FindingRequest
|
|
66
|
-
#
|
|
67
|
-
# @param request_dtm [Contrast::Api::Dtm::HttpRequest]
|
|
68
|
-
def attach_dtm_data request_dtm
|
|
69
|
-
@body = request_dtm.request_body_binary
|
|
70
|
-
@headers = {}
|
|
71
|
-
request_dtm.request_headers.each_pair do |key, value|
|
|
72
|
-
next unless key && value
|
|
73
|
-
|
|
74
|
-
# We need to change from the uppercase _ format to capitalized - format.
|
|
75
|
-
header = key.split('_')
|
|
76
|
-
header.each(&:capitalize!)
|
|
77
|
-
header = header.join('-')
|
|
78
|
-
headers[header] = value.split
|
|
79
|
-
end
|
|
80
|
-
@method = request_dtm.method # rubocop:disable Security/Object/Method
|
|
81
|
-
@parameters = {}
|
|
82
|
-
request_dtm.normalized_request_params.each_value do |pair|
|
|
83
|
-
@parameters[pair.key] = pair.values
|
|
84
|
-
end
|
|
85
|
-
@port = nil
|
|
86
|
-
@protocol = request_dtm.protocol
|
|
87
|
-
@query_string = request_dtm.query_string
|
|
88
|
-
@uri = request_dtm.uri
|
|
89
|
-
@version = request_dtm.version
|
|
90
|
-
end
|
|
91
|
-
|
|
92
65
|
# Convert the instance variables on the class, and other information, into the identifiers required for
|
|
93
66
|
# TeamServer to process the JSON form of this message.
|
|
94
67
|
#
|
|
@@ -110,7 +83,7 @@ module Contrast
|
|
|
110
83
|
end
|
|
111
84
|
|
|
112
85
|
def validate
|
|
113
|
-
unless
|
|
86
|
+
unless method && !method.empty? # rubocop:disable Security/Object/Method
|
|
114
87
|
raise(ArgumentError, "#{ self } did not have a proper method. Unable to continue.")
|
|
115
88
|
end
|
|
116
89
|
raise(ArgumentError, "#{ self } did not have a proper uri. Unable to continue.") unless uri && !uri.empty?
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'contrast/agent/reporting/reporting_events/reporting_event'
|
|
5
|
+
|
|
6
|
+
module Contrast
|
|
7
|
+
module Agent
|
|
8
|
+
module Reporting
|
|
9
|
+
# This is the new Poll class for the Heartbeat Service.
|
|
10
|
+
class Poll < Contrast::Agent::Reporting::ReportingEvent
|
|
11
|
+
def initialize
|
|
12
|
+
@event_type = :heartbeat
|
|
13
|
+
@event_endpoint = Contrast::Agent::Reporting::Endpoints.heartbeat
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# This is commented out as I am not aware if we're supposed to send some information and/or parse it to hash
|
|
18
|
+
# In https://github.com/Contrast-Security-Inc/contrast-service/blob/next/reporting/tsreporter.go
|
|
19
|
+
#
|
|
20
|
+
# Convert the instance variables on the class, and other information, into the identifiers required for
|
|
21
|
+
# TeamServer to process the JSON form of this message.
|
|
22
|
+
#
|
|
23
|
+
# @return [Hash]
|
|
24
|
+
# @raise [ArgumentError]
|
|
25
|
+
# def to_controlled_hash; end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -12,13 +12,14 @@ module Contrast
|
|
|
12
12
|
# reporting system.
|
|
13
13
|
#
|
|
14
14
|
# @abstract
|
|
15
|
-
# @attr_reader routes [Array]
|
|
16
|
-
# @attr_reader event_method [Symbol] the HTTP method to use to send this event
|
|
17
15
|
class ReportingEvent
|
|
18
|
-
|
|
16
|
+
# @return [String] the endpoint, with host, to which this event should be sent
|
|
17
|
+
attr_reader :event_endpoint
|
|
18
|
+
# @return event_method [Symbol] the HTTP method to use to send this event
|
|
19
|
+
attr_reader :event_method
|
|
19
20
|
|
|
20
21
|
def initialize
|
|
21
|
-
@agent_session_id_value = 0 # TODO: RUBY-
|
|
22
|
+
@agent_session_id_value = '0' # TODO: RUBY-1514 Contrast::APP_CONTEXT.session_id once we have app start
|
|
22
23
|
@event_endpoint ||= nil
|
|
23
24
|
@event_method ||= :POST
|
|
24
25
|
end
|
|
@@ -84,13 +84,13 @@ module Contrast
|
|
|
84
84
|
# Here we will generate the directories for the requests and responses
|
|
85
85
|
def generate_paths
|
|
86
86
|
message_directories = File.expand_path(path_to_audits)
|
|
87
|
-
|
|
87
|
+
make_directory(message_directories) unless Dir.exist?(message_directories)
|
|
88
88
|
|
|
89
89
|
requests_destination = File.expand_path(File.join(message_directories, '/requests'))
|
|
90
90
|
responses_destination = File.expand_path(File.join(message_directories, '/responses'))
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
92
|
+
make_directory(requests_destination) if enabled_for_requests? && !Dir.exist?(requests_destination)
|
|
93
|
+
make_directory(responses_destination) if enabled_for_responses? && !Dir.exist?(responses_destination)
|
|
94
94
|
|
|
95
95
|
@path_for_requests ||= requests_destination if enabled_for_requests?
|
|
96
96
|
@path_for_responses ||= responses_destination if enabled_for_responses?
|
|
@@ -98,6 +98,13 @@ module Contrast
|
|
|
98
98
|
logger.warn('Generating the paths failed with: ', e: e)
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
+
# Make the directory provided, including any required intermediary directories.
|
|
102
|
+
# We do this here in order to make allow us to easily override directory
|
|
103
|
+
# creation while testing.
|
|
104
|
+
def make_directory directory
|
|
105
|
+
FileUtils.mkdir_p(directory)
|
|
106
|
+
end
|
|
107
|
+
|
|
101
108
|
# Retrieves the configuration value if the request audit is enabled
|
|
102
109
|
# @return [Boolean]
|
|
103
110
|
def enabled?
|
|
@@ -57,6 +57,7 @@ module Contrast
|
|
|
57
57
|
# @return response [Net::HTTP::Response, nil] response from TS if no response
|
|
58
58
|
def send_event event, connection, send_immediately = false
|
|
59
59
|
return unless Contrast::Agent::Reporter.enabled?
|
|
60
|
+
return unless connection
|
|
60
61
|
|
|
61
62
|
response = send_events(event, connection)
|
|
62
63
|
log_send_event event if send_immediately
|
|
@@ -15,8 +15,35 @@ module Contrast
|
|
|
15
15
|
include Contrast::Components::Scope::InstanceMethods
|
|
16
16
|
include Contrast::Agent::Reporting::Endpoints
|
|
17
17
|
|
|
18
|
+
# @param event [Contrast::Agent::Reporting::Preflight] the preflight we handle here
|
|
19
|
+
# @param response [Net::HTTP::Response,nil] The response we handle and read from
|
|
20
|
+
# @param connection [Net::HTTP] open connection
|
|
21
|
+
def handle_response event, response, connection
|
|
22
|
+
return unless event && response && connection
|
|
23
|
+
return unless event.cs__is_a?(Contrast::Agent::Reporting::Preflight)
|
|
24
|
+
|
|
25
|
+
preflight_message = event.messages[0]
|
|
26
|
+
# for handling multiple findings
|
|
27
|
+
# we'll only extract the indexes without *
|
|
28
|
+
# findings_to_return = response.body.split(',').delete_if { |el| el.include?('*') }
|
|
29
|
+
# after that we'll do some magic and return them the same way we do for corresponding_finding
|
|
30
|
+
corresponding_finding = Contrast::Agent::Reporting::ReportingStorage.delete(preflight_message.hash_code)
|
|
31
|
+
return unless corresponding_finding
|
|
32
|
+
|
|
33
|
+
audit&.audit_event(corresponding_finding, response) if ::Contrast::API.request_audit_enable?
|
|
34
|
+
send_event(corresponding_finding, connection, true)
|
|
35
|
+
nil
|
|
36
|
+
rescue StandardError => e
|
|
37
|
+
logger.error('Unable to handle response', e)
|
|
38
|
+
end
|
|
39
|
+
|
|
18
40
|
private
|
|
19
41
|
|
|
42
|
+
# TODO: RUBY-1466 find better home for this?
|
|
43
|
+
def audit
|
|
44
|
+
@_audit ||= Contrast::Agent::Reporting::Audit.new
|
|
45
|
+
end
|
|
46
|
+
|
|
20
47
|
# This method will build headers of the request required for TS communication
|
|
21
48
|
#
|
|
22
49
|
# @param request [Net::HTTPRequest]
|
|
@@ -67,7 +94,7 @@ module Contrast
|
|
|
67
94
|
# @param response [Net::HTTP::Response]
|
|
68
95
|
# @return response [Net::HTTP::Response]
|
|
69
96
|
def process_response response
|
|
70
|
-
response_handler.process
|
|
97
|
+
response_handler.process(response)
|
|
71
98
|
logger.debug('Successfully sent startup messages to service.')
|
|
72
99
|
status.success!
|
|
73
100
|
response
|
|
@@ -129,25 +156,6 @@ module Contrast
|
|
|
129
156
|
end
|
|
130
157
|
|
|
131
158
|
# Eventually here we'll handle more response types and etc
|
|
132
|
-
|
|
133
|
-
# @param event [Contrast::Agent::Reporting::Preflight] the preflight we handle here
|
|
134
|
-
# @param response [Net::HTTP::Response,nil] The response we handle and read from
|
|
135
|
-
# @param connection [Net::HTTP] open connection
|
|
136
|
-
def handle_response event, response, connection
|
|
137
|
-
return unless event || response || connection
|
|
138
|
-
return unless event.cs__is_a?(Contrast::Agent::Reporting::Preflight)
|
|
139
|
-
|
|
140
|
-
preflight_message = event.messages[0]
|
|
141
|
-
# for handling multiple findings
|
|
142
|
-
# we'll only extract the indexes without *
|
|
143
|
-
# findings_to_return = response.body.split(',').delete_if { |el| el.include?('*') }
|
|
144
|
-
# after that we'll do some magic and return them the same way we do for corresponding_finding
|
|
145
|
-
corresponding_finding = Contrast::Agent::Reporting::ReportingStorage.delete(preflight_message.hash_code)
|
|
146
|
-
return unless corresponding_finding
|
|
147
|
-
|
|
148
|
-
send_event corresponding_finding, connection, true
|
|
149
|
-
nil
|
|
150
|
-
end
|
|
151
159
|
end
|
|
152
160
|
end
|
|
153
161
|
end
|
|
@@ -54,7 +54,7 @@ module Contrast
|
|
|
54
54
|
#
|
|
55
55
|
# @param response [Contrast::Agent::Reporting::Response]
|
|
56
56
|
def update_reaction response
|
|
57
|
-
return unless response.application_settings.reactions
|
|
57
|
+
return unless response.application_settings.reactions&.any?
|
|
58
58
|
|
|
59
59
|
response.application_settings.reactions.each do |reaction|
|
|
60
60
|
# The enums are all uppercase, we need to downcase them before attempting to log.
|
|
@@ -134,6 +134,8 @@ module Contrast
|
|
|
134
134
|
# @return res [Contrast::Agent::Reporting::Response]
|
|
135
135
|
def extract_assess response_data, res
|
|
136
136
|
assessments = response_data[:settings][:assessment]
|
|
137
|
+
return unless assessments
|
|
138
|
+
|
|
137
139
|
res.application_settings.assess.disabled_rules = assessments[:disabledRules]
|
|
138
140
|
res.application_settings.assess.session_id = assessments[:session_id]
|
|
139
141
|
end
|
|
@@ -142,6 +144,8 @@ module Contrast
|
|
|
142
144
|
# @return res [Contrast::Agent::Reporting::Response]
|
|
143
145
|
def extract_protect response_data, res
|
|
144
146
|
protect = response_data[:settings][:defend]
|
|
147
|
+
return unless protect
|
|
148
|
+
|
|
145
149
|
res.application_settings.protect.protection_rules = protect[:protectionRules]
|
|
146
150
|
res.application_settings.protect.virtual_patches = protect[:virtualPatches]
|
|
147
151
|
end
|
|
@@ -150,6 +154,8 @@ module Contrast
|
|
|
150
154
|
# @return res [Contrast::Agent::Reporting::Response]
|
|
151
155
|
def extract_exclusions response_data, res
|
|
152
156
|
exclusions = response_data[:settings][:exceptions]
|
|
157
|
+
return unless exclusions
|
|
158
|
+
|
|
153
159
|
res.application_settings.exclusions.code_exclusions = exclusions[:codeExceptions]
|
|
154
160
|
res.application_settings.exclusions.input_exclusions = exclusions[:inputExceptions]
|
|
155
161
|
res.application_settings.exclusions.url_exclusions = exclusions[:urlExceptions]
|
|
@@ -165,6 +171,8 @@ module Contrast
|
|
|
165
171
|
# @return res [Contrast::Agent::Reporting::Response]
|
|
166
172
|
def extract_assess_server_features response_data, res
|
|
167
173
|
assess = response_data[:assessment]
|
|
174
|
+
return unless assess
|
|
175
|
+
|
|
168
176
|
res.server_features.assess.enabled = assess[:enabled]
|
|
169
177
|
res.server_features.assess.disabled_rules = assess[:disabledRules]
|
|
170
178
|
res.server_features.assess.sampling = assess[:sampling]
|
|
@@ -176,6 +184,8 @@ module Contrast
|
|
|
176
184
|
# @return res [Contrast::Agent::Reporting::Response]
|
|
177
185
|
def extract_protect_server_features response_data, res
|
|
178
186
|
protect = response_data[:defend]
|
|
187
|
+
return unless protect
|
|
188
|
+
|
|
179
189
|
res.server_features.protect.enabled = protect[:enabled]
|
|
180
190
|
res.server_features.protect.bot_blocker = protect[:bot_blocker]
|
|
181
191
|
res.server_features.protect.syslog = protect[:syslog]
|
|
@@ -185,6 +195,8 @@ module Contrast
|
|
|
185
195
|
# @return res [Contrast::Agent::Reporting::Response]
|
|
186
196
|
def extract_protect_lists response_data, res
|
|
187
197
|
protect = response_data[:defend]
|
|
198
|
+
return unless protect
|
|
199
|
+
|
|
188
200
|
res.server_features.protect.ip_allowlist = protect[:ipAllowlist]
|
|
189
201
|
res.server_features.protect.ip_denylist = protect[:ipDenyList]
|
|
190
202
|
res.server_features.protect.log_enchancers = protect[:logEnhancers]
|