contrast-agent 6.6.5 → 6.7.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 +3 -0
- data/.gitmodules +0 -3
- data/ext/cs__scope/cs__scope.c +1 -1
- data/lib/contrast/agent/assess/contrast_event.rb +2 -24
- data/lib/contrast/agent/assess/events/source_event.rb +7 -61
- data/lib/contrast/agent/assess/finalizers/hash.rb +11 -0
- data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +0 -55
- data/lib/contrast/agent/assess/policy/policy_node.rb +3 -3
- data/lib/contrast/agent/assess/policy/policy_node_utils.rb +0 -1
- data/lib/contrast/agent/assess/policy/propagation_node.rb +4 -4
- data/lib/contrast/agent/assess/policy/source_method.rb +24 -1
- data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +7 -5
- data/lib/contrast/agent/assess/policy/trigger/xpath.rb +6 -1
- data/lib/contrast/agent/assess/policy/trigger_method.rb +36 -132
- data/lib/contrast/agent/assess/policy/trigger_node.rb +3 -3
- data/lib/contrast/agent/assess/property/evented.rb +2 -12
- data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +42 -84
- data/lib/contrast/agent/assess/rule/response/base_rule.rb +11 -27
- data/lib/contrast/agent/assess/rule/response/body_rule.rb +1 -3
- data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +77 -62
- data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +1 -1
- data/lib/contrast/agent/assess/rule/response/framework/rails_support.rb +6 -1
- data/lib/contrast/agent/assess/rule/response/header_rule.rb +5 -5
- data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +1 -1
- data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +1 -1
- data/lib/contrast/agent/assess/tracker.rb +1 -7
- data/lib/contrast/agent/excluder.rb +206 -0
- data/lib/contrast/agent/exclusion_matcher.rb +6 -0
- data/lib/contrast/agent/inventory/database_config.rb +6 -10
- data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +4 -0
- data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +1 -0
- data/lib/contrast/agent/protect/rule/base.rb +49 -5
- data/lib/contrast/agent/protect/rule/base_service.rb +1 -0
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +18 -105
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +129 -0
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +169 -0
- data/lib/contrast/agent/protect/rule/deserialization.rb +2 -1
- data/lib/contrast/agent/protect/rule/sqli/sqli_base_rule.rb +51 -0
- data/lib/contrast/agent/protect/rule/sqli/sqli_semantic/sqli_dangerous_functions.rb +67 -0
- data/lib/contrast/agent/protect/rule/sqli.rb +6 -31
- data/lib/contrast/agent/protect/rule/xxe.rb +2 -0
- data/lib/contrast/agent/protect/rule.rb +3 -1
- data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +6 -0
- data/lib/contrast/agent/reporting/details/sqli_dangerous_functions.rb +22 -0
- data/lib/contrast/agent/reporting/reporter.rb +1 -2
- data/lib/contrast/agent/reporting/reporting_events/agent_startup.rb +2 -2
- data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +1 -4
- data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +0 -23
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +19 -49
- data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +12 -9
- data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +23 -21
- data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +5 -18
- data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +1 -0
- data/lib/contrast/{api/decorators/trace_taint_range_tags.rb → agent/reporting/reporting_events/finding_event_taint_range_tags.rb} +7 -6
- data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +2 -2
- data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +10 -14
- data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +11 -0
- data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +3 -1
- data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +11 -23
- data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +8 -26
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +4 -7
- data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +3 -3
- data/lib/contrast/agent/request.rb +2 -2
- data/lib/contrast/agent/request_context.rb +8 -20
- data/lib/contrast/agent/request_context_extend.rb +15 -36
- data/lib/contrast/agent/request_handler.rb +0 -8
- data/lib/contrast/agent/response.rb +0 -18
- data/lib/contrast/agent/telemetry/events/event.rb +1 -1
- data/lib/contrast/agent/telemetry/events/metric_event.rb +1 -1
- data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +3 -3
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/communication/messaging_queue.rb +2 -3
- data/lib/contrast/api/communication/socket_client.rb +4 -4
- data/lib/contrast/api/communication/speedracer.rb +4 -8
- data/lib/contrast/api/decorators/agent_startup.rb +5 -6
- data/lib/contrast/api/decorators/application_settings.rb +2 -1
- data/lib/contrast/api/decorators/application_startup.rb +6 -6
- data/lib/contrast/api/decorators/message.rb +0 -4
- data/lib/contrast/api/decorators/rasp_rule_sample.rb +0 -6
- data/lib/contrast/api/decorators.rb +0 -6
- data/lib/contrast/api/dtm.pb.rb +0 -489
- data/lib/contrast/components/agent.rb +16 -12
- data/lib/contrast/components/api.rb +10 -10
- data/lib/contrast/components/app_context.rb +3 -3
- data/lib/contrast/components/app_context_extend.rb +1 -1
- data/lib/contrast/components/assess.rb +92 -38
- data/lib/contrast/components/assess_rules.rb +36 -0
- data/lib/contrast/components/config.rb +54 -12
- data/lib/contrast/components/contrast_service.rb +8 -8
- data/lib/contrast/components/heap_dump.rb +1 -1
- data/lib/contrast/components/protect.rb +5 -5
- data/lib/contrast/components/ruby_component.rb +81 -0
- data/lib/contrast/components/sampling.rb +1 -1
- data/lib/contrast/components/security_logger.rb +23 -0
- data/lib/contrast/components/service.rb +55 -0
- data/lib/contrast/components/settings.rb +12 -4
- data/lib/contrast/config/base_configuration.rb +1 -1
- data/lib/contrast/config/protect_rules_configuration.rb +17 -3
- data/lib/contrast/config/server_configuration.rb +1 -1
- data/lib/contrast/config.rb +0 -6
- data/lib/contrast/configuration.rb +81 -17
- data/lib/contrast/extension/assess/exec_trigger.rb +3 -1
- data/lib/contrast/extension/assess/marshal.rb +3 -2
- data/lib/contrast/extension/assess/string.rb +0 -1
- data/lib/contrast/extension/extension.rb +1 -1
- data/lib/contrast/framework/base_support.rb +0 -5
- data/lib/contrast/framework/grape/support.rb +1 -23
- data/lib/contrast/framework/manager.rb +0 -10
- data/lib/contrast/framework/rails/support.rb +5 -58
- data/lib/contrast/framework/sinatra/support.rb +2 -21
- data/lib/contrast/logger/cef_log.rb +21 -3
- data/lib/contrast/logger/log.rb +1 -11
- data/lib/contrast/tasks/config.rb +4 -2
- data/lib/contrast/utils/assess/event_limit_utils.rb +5 -8
- data/lib/contrast/utils/assess/trigger_method_utils.rb +10 -18
- data/lib/contrast/utils/findings.rb +6 -5
- data/lib/contrast/utils/hash_digest.rb +9 -24
- data/lib/contrast/utils/hash_digest_extend.rb +6 -6
- data/lib/contrast/utils/invalid_configuration_util.rb +21 -58
- data/lib/contrast/utils/log_utils.rb +32 -8
- data/lib/contrast/utils/net_http_base.rb +2 -2
- data/lib/contrast/utils/patching/policy/patch_utils.rb +3 -2
- data/lib/contrast/utils/stack_trace_utils.rb +0 -25
- data/lib/contrast/utils/string_utils.rb +9 -0
- data/lib/contrast/utils/telemetry_client.rb +13 -7
- data/lib/contrast.rb +5 -10
- metadata +22 -28
- data/lib/contrast/agent/reporting/reporting_events/trace_event_source.rb +0 -30
- data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -36
- data/lib/contrast/api/decorators/activity.rb +0 -33
- data/lib/contrast/api/decorators/architecture_component.rb +0 -36
- data/lib/contrast/api/decorators/finding.rb +0 -29
- data/lib/contrast/api/decorators/route_coverage.rb +0 -91
- data/lib/contrast/api/decorators/trace_event.rb +0 -120
- data/lib/contrast/api/decorators/trace_event_object.rb +0 -63
- data/lib/contrast/api/decorators/trace_event_signature.rb +0 -69
- data/lib/contrast/api/decorators/trace_taint_range.rb +0 -52
- data/lib/contrast/config/assess_configuration.rb +0 -93
- data/lib/contrast/config/assess_rules_configuration.rb +0 -32
- data/lib/contrast/config/root_configuration.rb +0 -90
- data/lib/contrast/config/ruby_configuration.rb +0 -81
- data/lib/contrast/config/service_configuration.rb +0 -49
- data/lib/contrast/utils/preflight_util.rb +0 -13
|
@@ -1,9 +1,10 @@
|
|
|
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/reporting_events/reporting_event'
|
|
4
5
|
require 'contrast/components/assess'
|
|
5
6
|
require 'contrast/components/logger'
|
|
6
|
-
require 'contrast/
|
|
7
|
+
require 'contrast/utils/string_utils'
|
|
7
8
|
|
|
8
9
|
module Contrast
|
|
9
10
|
module Agent
|
|
@@ -13,6 +14,8 @@ module Contrast
|
|
|
13
14
|
# identifying information of a Finding/Trace, which TeamServer will use to determine if it requires the full
|
|
14
15
|
# information of the Finding/Trace to be reported.
|
|
15
16
|
class PreflightMessage
|
|
17
|
+
include Contrast::Components::Logger::InstanceMethods
|
|
18
|
+
|
|
16
19
|
# @return [String] the message identifier; rule_id,hash
|
|
17
20
|
attr_accessor :data
|
|
18
21
|
# @return [String] CRC checksum of the finding to which this message pertains
|
|
@@ -26,9 +29,6 @@ module Contrast
|
|
|
26
29
|
CODE = :TRACE
|
|
27
30
|
|
|
28
31
|
def initialize
|
|
29
|
-
@app_language = Contrast::Utils::ObjectShare::RUBY
|
|
30
|
-
@app_name = ::Contrast::APP_CONTEXT.name # rubocop:disable Security/Module/Name
|
|
31
|
-
@app_version = ::Contrast::APP_CONTEXT.version
|
|
32
32
|
@routes = []
|
|
33
33
|
end
|
|
34
34
|
|
|
@@ -47,24 +47,20 @@ module Contrast
|
|
|
47
47
|
|
|
48
48
|
{
|
|
49
49
|
code: CODE,
|
|
50
|
-
app_language:
|
|
51
|
-
app_name:
|
|
52
|
-
app_version:
|
|
50
|
+
app_language: Contrast::Utils::ObjectShare::RUBY,
|
|
51
|
+
app_name: ::Contrast::APP_CONTEXT.name, # rubocop:disable Security/Module/Name
|
|
52
|
+
app_version: ::Contrast::APP_CONTEXT.version,
|
|
53
53
|
data: '',
|
|
54
54
|
key: 0,
|
|
55
|
-
routes: @routes,
|
|
55
|
+
routes: @routes.map(&:to_controlled_hash),
|
|
56
56
|
session_id: ::Contrast::ASSESS.session_id
|
|
57
57
|
}
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
# @raise [ArgumentError]
|
|
61
61
|
def validate
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
raise(ArgumentError, "#{ cs__class } did not have a proper application name. Unable to continue.")
|
|
65
|
-
end
|
|
66
|
-
unless @app_language
|
|
67
|
-
raise(ArgumentError, "#{ cs__class } did not have a proper application language. Unable to continue.")
|
|
62
|
+
unless Contrast::Utils::StringUtils.present?(data)
|
|
63
|
+
raise(ArgumentError, "#{ cs__class } did not have a proper data. Unable to continue.")
|
|
68
64
|
end
|
|
69
65
|
unless ::Contrast::ASSESS.session_id
|
|
70
66
|
raise(ArgumentError, "#{ cs__class } did not have a proper session id. Unable to continue.")
|
|
@@ -49,6 +49,17 @@ module Contrast
|
|
|
49
49
|
|
|
50
50
|
# @raise [ArgumentError]
|
|
51
51
|
def validate; end
|
|
52
|
+
|
|
53
|
+
# Helper method to get json representation of event and handle errors
|
|
54
|
+
#
|
|
55
|
+
# @return [String] - JSON
|
|
56
|
+
def event_json
|
|
57
|
+
hsh = to_controlled_hash
|
|
58
|
+
hsh.to_json
|
|
59
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
60
|
+
logger.error('Unable to convert JSON string', e, hsh)
|
|
61
|
+
raise(e)
|
|
62
|
+
end
|
|
52
63
|
end
|
|
53
64
|
end
|
|
54
65
|
end
|
|
@@ -42,7 +42,9 @@ module Contrast
|
|
|
42
42
|
# @param url [String] the literal url of the route actively being executed
|
|
43
43
|
# @return [Contrast::Agent::Reporting::RouteCoverage]
|
|
44
44
|
def attach_rack_based_data final_controller, method, route_pattern, url = nil
|
|
45
|
-
if
|
|
45
|
+
if Contrast::Utils::ClassUtil.truly_defined?('Grape::Router::Route') &&
|
|
46
|
+
route_pattern.cs__is_a?(Grape::Router::Route)
|
|
47
|
+
|
|
46
48
|
safe_pattern = route_pattern.pattern&.path&.to_s
|
|
47
49
|
safe_url = source_or_string(url || safe_pattern)
|
|
48
50
|
else
|
|
@@ -14,34 +14,22 @@ module Contrast
|
|
|
14
14
|
# externally accessible endpoints within the application, as registered to the application framework. They may or
|
|
15
15
|
# may not have been invoked at the time of reporting.
|
|
16
16
|
#
|
|
17
|
-
# @attr_reader observations [observations] the routes and verbs seen that match to this Route
|
|
18
|
-
# @attr_reader signature [String] the unique identifier for this route; typically the method signature. Required
|
|
19
|
-
# for reporting.
|
|
20
17
|
class RouteDiscovery
|
|
21
18
|
include Contrast::Components::Logger::InstanceMethods
|
|
22
19
|
|
|
23
|
-
#
|
|
24
|
-
|
|
20
|
+
# @return [Array<Contrast::Agent::Reporting::RouteDiscoveryObservation>] the routes and verbs seen that match
|
|
21
|
+
# to this Route.
|
|
22
|
+
attr_reader :observations
|
|
23
|
+
# @return [String] the unique identifier for this route; typically the method signature. Required for
|
|
24
|
+
# reporting.
|
|
25
|
+
attr_accessor :signature
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# @return [Contrast::Agent::Reporting::RouteDiscovery]
|
|
31
|
-
def convert route_coverage_dtm
|
|
32
|
-
report = new
|
|
33
|
-
report.attach_data(route_coverage_dtm)
|
|
34
|
-
report
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
# Attach the data from the protobuf models to this reporter so that it can be sent to TeamServer directly
|
|
39
|
-
#
|
|
40
|
-
# @param route_coverage_dtm [Contrast::Api::Dtm::RouteCoverage]
|
|
41
|
-
def attach_data route_coverage_dtm
|
|
42
|
-
@signature = route_coverage_dtm.route
|
|
27
|
+
# @param signature [String]
|
|
28
|
+
# @param observation [Contrast::Agent::Reporting::RouteDiscoveryObservation]
|
|
29
|
+
def initialize signature, observation
|
|
30
|
+
@signature = signature
|
|
43
31
|
@observations = []
|
|
44
|
-
observations <<
|
|
32
|
+
observations << observation
|
|
45
33
|
end
|
|
46
34
|
|
|
47
35
|
# Convert the instance variables on the class, and other information, into the identifiers required for
|
|
@@ -12,36 +12,18 @@ module Contrast
|
|
|
12
12
|
# reporting system to relay this information in the Application Update messages. These route observations are
|
|
13
13
|
# used by TeamServer to construct the route coverage information for the assess feature. They represent the
|
|
14
14
|
# literal URL and HTTP verb used to invoke a method in the application, as routed by the application framework.
|
|
15
|
-
#
|
|
16
|
-
# @attr_reader url [String] the URL requested to hit this endpoint. Required for reporting.
|
|
17
|
-
# @attr_reader verb [String] the HTTP Method requested to his this endpoint. Empty means all, so is allowed.
|
|
18
|
-
# for reporting.
|
|
19
15
|
class RouteDiscoveryObservation
|
|
20
16
|
include Contrast::Components::Logger::InstanceMethods
|
|
21
17
|
|
|
22
|
-
# required attributes
|
|
23
|
-
|
|
24
|
-
#
|
|
25
|
-
|
|
18
|
+
# @return [String] the URL requested to hit this endpoint. Required for reporting; required attributes
|
|
19
|
+
attr_accessor :url
|
|
20
|
+
# @return [String] the HTTP Method requested to his this endpoint. Empty means all, so is allowed for
|
|
21
|
+
# reporting; optional attributes
|
|
22
|
+
attr_accessor :verb
|
|
26
23
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
# @param route_coverage_dtm [Contrast::Api::Dtm::RouteCoverage]
|
|
31
|
-
# @return [Contrast::Agent::Reporting::RouteDiscoveryObservation]
|
|
32
|
-
def convert route_coverage_dtm
|
|
33
|
-
report = new
|
|
34
|
-
report.attach_data(route_coverage_dtm)
|
|
35
|
-
report
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Attach the data from the protobuf models to this reporter so that it can be sent to TeamServer directly
|
|
40
|
-
#
|
|
41
|
-
# @param route_coverage_dtm [Contrast::Api::Dtm::RouteCoverage]
|
|
42
|
-
def attach_data route_coverage_dtm
|
|
43
|
-
@url = route_coverage_dtm.url
|
|
44
|
-
@verb = route_coverage_dtm.verb if Contrast::Utils::StringUtils.present?(route_coverage_dtm.verb)
|
|
24
|
+
def initialize url, verb
|
|
25
|
+
@url = url
|
|
26
|
+
@verb = verb if Contrast::Utils::StringUtils.present?(verb)
|
|
45
27
|
end
|
|
46
28
|
|
|
47
29
|
# Convert the instance variables on the class, and other information, into the identifiers required for
|
|
@@ -29,7 +29,7 @@ module Contrast
|
|
|
29
29
|
return unless ::Contrast::API.request_audit_requests || ::Contrast::API.request_audit_responses
|
|
30
30
|
|
|
31
31
|
file_name = event.cs__respond_to?(:file_name) ? event.file_name : event.cs__class.cs__name.to_s.downcase
|
|
32
|
-
data = event.
|
|
32
|
+
data = event.event_json
|
|
33
33
|
log_data(:request, file_name, data) if data
|
|
34
34
|
return unless ::Contrast::API.request_audit_responses
|
|
35
35
|
|
|
@@ -14,17 +14,14 @@ module Contrast
|
|
|
14
14
|
module BuildPreflight
|
|
15
15
|
class << self
|
|
16
16
|
# @param finding [Contrast::Agent::Reporting::Finding]
|
|
17
|
-
# @
|
|
18
|
-
def
|
|
17
|
+
# @return [Contrast::Agent::Reporting::Preflight, nil]
|
|
18
|
+
def generate finding
|
|
19
19
|
return unless finding
|
|
20
20
|
|
|
21
|
-
# save the current finding
|
|
22
|
-
Contrast::Agent::Reporting::ReportingStorage[finding.hash_code] = finding
|
|
23
|
-
|
|
24
21
|
new_preflight = Contrast::Agent::Reporting::Preflight.new
|
|
25
22
|
new_preflight_message = Contrast::Agent::Reporting::PreflightMessage.new
|
|
26
|
-
|
|
27
|
-
new_preflight_message.routes <<
|
|
23
|
+
finding.routes.each do |route|
|
|
24
|
+
new_preflight_message.routes << route
|
|
28
25
|
end
|
|
29
26
|
new_preflight_message.hash_code = finding.hash_code
|
|
30
27
|
new_preflight_message.data = "#{ finding.rule_id },#{ finding.hash_code }"
|
|
@@ -69,7 +69,7 @@ module Contrast
|
|
|
69
69
|
# Handles standard error case, logs and set status for failure
|
|
70
70
|
#
|
|
71
71
|
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
|
72
|
-
#
|
|
72
|
+
# One of the DTMs valid for the event field of Contrast::Api::Dtm::Message
|
|
73
73
|
# @param error_msg [StandardError]
|
|
74
74
|
# @return nil [NilClass] to be passed as response
|
|
75
75
|
def handle_error event, error_msg
|
|
@@ -105,7 +105,7 @@ module Contrast
|
|
|
105
105
|
findings_to_return = response.body.split(',').delete_if { |el| el.include?('*') }
|
|
106
106
|
findings_to_return.each do |index|
|
|
107
107
|
preflight_message = event.messages[index.to_i]
|
|
108
|
-
corresponding_finding = Contrast::Agent::Reporting::ReportingStorage.delete(preflight_message.
|
|
108
|
+
corresponding_finding = Contrast::Agent::Reporting::ReportingStorage.delete(preflight_message.data)
|
|
109
109
|
next unless corresponding_finding
|
|
110
110
|
|
|
111
111
|
send_event(corresponding_finding, connection)
|
|
@@ -130,7 +130,7 @@ module Contrast
|
|
|
130
130
|
end
|
|
131
131
|
build_headers(request)
|
|
132
132
|
event.attach_headers(request)
|
|
133
|
-
request.body = event.
|
|
133
|
+
request.body = event.event_json
|
|
134
134
|
request
|
|
135
135
|
end
|
|
136
136
|
end
|
|
@@ -33,10 +33,10 @@ module Contrast
|
|
|
33
33
|
|
|
34
34
|
# @return [Rack::Request] The passed to the Agent RackRequest to be wrapped.
|
|
35
35
|
attr_reader :rack_request
|
|
36
|
-
# @return [Contrast::Api::Dtm::RouteCoverage] the route, used for findings, of this request
|
|
37
|
-
attr_accessor :route
|
|
38
36
|
# @return [Contrast::Agent::Reporting::ObservedRoute] the route, used for coverage, of this request
|
|
39
37
|
attr_accessor :observed_route
|
|
38
|
+
# @return [Contrast::Agent::Reporting::RouteDiscovery]
|
|
39
|
+
attr_accessor :discovered_route
|
|
40
40
|
|
|
41
41
|
# Delegate calls to the following methods to the attribute @rack_request
|
|
42
42
|
def_delegators :@rack_request, :base_url, :cookies, :env, :ip, :media_type, :path, :port, :query_string,
|
|
@@ -28,10 +28,6 @@ module Contrast
|
|
|
28
28
|
|
|
29
29
|
# @return [Contrast::Agent::Reporting:ApplicationActivity] the application activity found in this request
|
|
30
30
|
attr_reader :activity
|
|
31
|
-
# REMOVE once findings and routes are done.
|
|
32
|
-
#
|
|
33
|
-
# @return [Contrast::Api::Dtm::Activity] the application activity found in this request
|
|
34
|
-
attr_reader :dtm_activity
|
|
35
31
|
# @return [Hash] context used to log the request
|
|
36
32
|
attr_reader :logging_hash
|
|
37
33
|
# @return [Contrast::Agent::Reporting::ObservedRoute] the route, used for coverage, of this request
|
|
@@ -41,10 +37,12 @@ module Contrast
|
|
|
41
37
|
# @return [Contrast::Agent::Response] our wrapper around the Rack::Response or Array for this context,
|
|
42
38
|
# only available after the application has finished its processing
|
|
43
39
|
attr_reader :response
|
|
44
|
-
# @return [Contrast::
|
|
45
|
-
attr_reader :
|
|
40
|
+
# @return [Contrast::Agent::Reporting::RouteDiscovery] the route, used for findings, of this request
|
|
41
|
+
attr_reader :discovered_route
|
|
46
42
|
# @return [Contrast::Api::Settings::InputAnalysis] the protect input analysis of sources on this request
|
|
47
43
|
attr_reader :speedracer_input_analysis
|
|
44
|
+
# @return [Array<String>] the hash of findings already reported fro this request
|
|
45
|
+
attr_reader :reported_findings
|
|
48
46
|
# @return [Contrast::Utils::Timer] when the context was created
|
|
49
47
|
attr_reader :timer
|
|
50
48
|
|
|
@@ -60,12 +58,6 @@ module Contrast
|
|
|
60
58
|
@request = Contrast::Agent::Request.new(rack_request)
|
|
61
59
|
@activity = Contrast::Agent::Reporting::ApplicationActivity.new
|
|
62
60
|
|
|
63
|
-
# REMOVE once findings and routes are done.
|
|
64
|
-
#
|
|
65
|
-
# We still need the activity to report routes and findings
|
|
66
|
-
@dtm_activity = Contrast::Api::Dtm::Activity.new
|
|
67
|
-
@dtm_activity.http_request = request.dtm
|
|
68
|
-
|
|
69
61
|
# build analyzer
|
|
70
62
|
@do_not_track = false
|
|
71
63
|
@speedracer_input_analysis = EMPTY_INPUT_ANALYSIS_PB
|
|
@@ -89,6 +81,8 @@ module Contrast
|
|
|
89
81
|
@sample_req, @sample_res = Contrast::Utils::Assess::SamplingUtil.instance.sample?(@request)
|
|
90
82
|
end
|
|
91
83
|
|
|
84
|
+
@reported_findings = []
|
|
85
|
+
|
|
92
86
|
handle_routes
|
|
93
87
|
end
|
|
94
88
|
end
|
|
@@ -142,14 +136,8 @@ module Contrast
|
|
|
142
136
|
|
|
143
137
|
def handle_routes
|
|
144
138
|
@observed_route = Contrast::Agent::Reporting::ObservedRoute.new
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
route_dtm = Contrast::Agent.framework_manager.get_route_dtm(@request)
|
|
148
|
-
# new_route_coverage_dtm = Contrast::Agent.framework_manager.get_route_information(@request)
|
|
149
|
-
# TODO: RUBY-1705 -- delete append_route_coverage
|
|
150
|
-
append_route_coverage(route_dtm)
|
|
151
|
-
# TODO: RUBY-1705 -- change to take [Contrast::Agent::Reporting::ObservedRoute]
|
|
152
|
-
append_to_observed_route(route_dtm)
|
|
139
|
+
reporting_route = Contrast::Agent.framework_manager.get_route_information(@request)
|
|
140
|
+
append_to_observed_route(reporting_route)
|
|
153
141
|
end
|
|
154
142
|
end
|
|
155
143
|
end
|
|
@@ -13,6 +13,7 @@ require 'contrast/agent/assess/rule/response/x_xss_protection_header_rule'
|
|
|
13
13
|
require 'contrast/agent/protect/input_analyzer/input_analyzer'
|
|
14
14
|
require 'contrast/components/logger'
|
|
15
15
|
require 'contrast/utils/log_utils'
|
|
16
|
+
require 'contrast/utils/string_utils'
|
|
16
17
|
|
|
17
18
|
module Contrast
|
|
18
19
|
module Agent
|
|
@@ -24,30 +25,11 @@ module Contrast
|
|
|
24
25
|
include Contrast::Components::Logger::InstanceMethods
|
|
25
26
|
BUILD_ATTACK_LOGGER_MESSAGE = 'Building attack result from Contrast Service input analysis result'
|
|
26
27
|
CEF_LOGGING_RULES = %w[bot-blocker virtual-patch ip-denylist].cs__freeze
|
|
27
|
-
# Convert the discovered route for this request to appropriate forms and disseminate it to those locations
|
|
28
|
-
# where it is necessary for our route coverage and finding vulnerability discovery features to function.
|
|
29
|
-
#
|
|
30
|
-
# @param route [Contrast::Api::Dtm::RouteCoverage, nil] the route of the current request, as determined from the
|
|
31
|
-
# framework
|
|
32
|
-
def append_route_coverage route
|
|
33
|
-
return unless route
|
|
34
|
-
|
|
35
|
-
# For our findings
|
|
36
|
-
@route = route
|
|
37
|
-
|
|
38
|
-
# REMOVE_DTM_ACTIVITY
|
|
39
|
-
#
|
|
40
|
-
# For SR findings
|
|
41
|
-
@dtm_activity.routes << route
|
|
42
|
-
|
|
43
|
-
# For TS routes
|
|
44
|
-
@request.route = route
|
|
45
|
-
end
|
|
46
28
|
|
|
47
29
|
# Convert the discovered route for this request to appropriate forms and disseminate it to those locations
|
|
48
30
|
# where it is necessary for our route coverage and finding vulnerability discovery features to function.
|
|
49
31
|
#
|
|
50
|
-
# @param route [Contrast::
|
|
32
|
+
# @param route [Contrast::Agent::Reporting::RouteCoverage]
|
|
51
33
|
def append_to_observed_route route
|
|
52
34
|
return unless route
|
|
53
35
|
|
|
@@ -55,6 +37,10 @@ module Contrast
|
|
|
55
37
|
@observed_route.verb = route.verb
|
|
56
38
|
@observed_route.url = route.url if route.url
|
|
57
39
|
@request.observed_route = @observed_route
|
|
40
|
+
|
|
41
|
+
observation = Contrast::Agent::Reporting::RouteDiscoveryObservation.new(route.url, route.verb)
|
|
42
|
+
@discovered_route = Contrast::Agent::Reporting::RouteDiscovery.new(route.route, observation)
|
|
43
|
+
@request.discovered_route = @discovered_route
|
|
58
44
|
end
|
|
59
45
|
|
|
60
46
|
# @raise [Contrast::SecurityException]
|
|
@@ -63,7 +49,6 @@ module Contrast
|
|
|
63
49
|
return false unless ::Contrast::PROTECT.enabled?
|
|
64
50
|
return false if @do_not_track
|
|
65
51
|
|
|
66
|
-
# REMOVE_DTM_ACTIVITY
|
|
67
52
|
service_response = Contrast::Agent&.messaging_queue&.send_event_immediately(@activity.request.dtm)
|
|
68
53
|
return false unless service_response
|
|
69
54
|
|
|
@@ -117,21 +102,15 @@ module Contrast
|
|
|
117
102
|
@response = Contrast::Agent::Response.new(rack_response)
|
|
118
103
|
return unless @sample_res
|
|
119
104
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
Contrast::Agent::Assess::Rule::Response::XContentType.new.analyze(@response)
|
|
130
|
-
Contrast::Agent::Assess::Rule::Response::XXssProtection.new.analyze(@response)
|
|
131
|
-
else
|
|
132
|
-
# REMOVE_DTM_ACTIVITY
|
|
133
|
-
dtm_activity.http_response = @response.dtm
|
|
134
|
-
end
|
|
105
|
+
Contrast::Agent::Assess::Rule::Response::AutoComplete.new.analyze(@response)
|
|
106
|
+
Contrast::Agent::Assess::Rule::Response::CacheControl.new.analyze(@response)
|
|
107
|
+
Contrast::Agent::Assess::Rule::Response::ClickJacking.new.analyze(@response)
|
|
108
|
+
Contrast::Agent::Assess::Rule::Response::CspHeaderMissing.new.analyze(@response)
|
|
109
|
+
Contrast::Agent::Assess::Rule::Response::CspHeaderInsecure.new.analyze(@response)
|
|
110
|
+
Contrast::Agent::Assess::Rule::Response::HSTSHeader.new.analyze(@response)
|
|
111
|
+
Contrast::Agent::Assess::Rule::Response::ParametersPollution.new.analyze(@response)
|
|
112
|
+
Contrast::Agent::Assess::Rule::Response::XContentType.new.analyze(@response)
|
|
113
|
+
Contrast::Agent::Assess::Rule::Response::XXssProtection.new.analyze(@response)
|
|
135
114
|
rescue StandardError => e
|
|
136
115
|
logger.error('Unable to extract information after request', e)
|
|
137
116
|
end
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
require 'contrast/components/logger'
|
|
5
5
|
require 'contrast/components/scope'
|
|
6
6
|
require 'contrast/agent/reporting/reporter'
|
|
7
|
-
require 'contrast/agent/reporting/reporting_utilities/dtm_message'
|
|
8
7
|
require 'contrast/agent/reporting/masker/masker'
|
|
9
8
|
|
|
10
9
|
module Contrast
|
|
@@ -30,13 +29,6 @@ module Contrast
|
|
|
30
29
|
return unless (reporter = Contrast::Agent.reporter)
|
|
31
30
|
|
|
32
31
|
reporter.send_event(context.observed_route)
|
|
33
|
-
# return unless Contrast::Agent::Reporter.enabled?
|
|
34
|
-
|
|
35
|
-
# REMOVE_DTM_ACTIVITY after reporter routes, responses, findings are implemented
|
|
36
|
-
#
|
|
37
|
-
# This reports routes, findings and traces with response dependent rules.
|
|
38
|
-
Contrast::Agent.messaging_queue&.send_event_eventually(context.dtm_activity)
|
|
39
|
-
|
|
40
32
|
# Mask Sensitive Data
|
|
41
33
|
Contrast::Agent::Reporting::Masker.mask(context.activity)
|
|
42
34
|
event = context.activity
|
|
@@ -45,24 +45,6 @@ module Contrast
|
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
47
|
|
|
48
|
-
# A form of the Rack::Response which we can report to the Service to be sent to TeamServer for processing. B/c
|
|
49
|
-
# the response can change, we can't memoize this :(
|
|
50
|
-
#
|
|
51
|
-
# @return [Contrast::Api::Dtm::HttpResponse]
|
|
52
|
-
def dtm
|
|
53
|
-
context_response = Contrast::Api::Dtm::HttpResponse.new
|
|
54
|
-
context_response.response_code = response_code.to_i
|
|
55
|
-
headers&.each_pair do |key, value|
|
|
56
|
-
append_pair(context_response.normalized_response_headers, key, value)
|
|
57
|
-
end
|
|
58
|
-
context_response.response_body_binary = Contrast::Utils::StringUtils.force_utf8(body)
|
|
59
|
-
|
|
60
|
-
doc_type = document_type
|
|
61
|
-
context_response.document_type = doc_type if doc_type
|
|
62
|
-
|
|
63
|
-
context_response
|
|
64
|
-
end
|
|
65
|
-
|
|
66
48
|
# The response code of this response
|
|
67
49
|
#
|
|
68
50
|
# @return [Integer]
|
|
@@ -50,7 +50,7 @@ module Contrast
|
|
|
50
50
|
def initialize
|
|
51
51
|
super
|
|
52
52
|
@settings = []
|
|
53
|
-
add_config_keys(::Contrast::CONFIG.
|
|
53
|
+
add_config_keys(::Contrast::CONFIG.config, 'root')
|
|
54
54
|
@settings << ENV.keys.select { |v| v.starts_with?('CONTRAST') }
|
|
55
55
|
@settings.flatten
|
|
56
56
|
add_tags
|
|
@@ -70,9 +70,9 @@ module Contrast
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def add_config_keys config, nested_key
|
|
73
|
-
config.
|
|
73
|
+
config.to_contrast_hash.reject! { |_k, v| REJECTED_VALUES.include?(v) }
|
|
74
74
|
|
|
75
|
-
config.
|
|
75
|
+
config.to_contrast_hash.each do |k, v|
|
|
76
76
|
unless v.cs__class <= Contrast::Config::BaseConfiguration
|
|
77
77
|
@settings << "#{ nested_key }.#{ k }"
|
|
78
78
|
next
|
|
@@ -29,8 +29,7 @@ module Contrast
|
|
|
29
29
|
# types of events include initial settings/ setup on startup and analysis required to complete before handing
|
|
30
30
|
# execution from our pre-filter operations to the application code (i.e. Protect's input analysis).
|
|
31
31
|
#
|
|
32
|
-
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of
|
|
33
|
-
# Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
|
|
32
|
+
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of Contrast::Api::Dtm::Message
|
|
34
33
|
# @return [Contrast::Api::Settings::AgentSettings,nil]
|
|
35
34
|
def send_event_immediately event
|
|
36
35
|
if ::Contrast::AGENT.disabled?
|
|
@@ -59,7 +58,7 @@ module Contrast
|
|
|
59
58
|
# Assess' vulnerability reporting).
|
|
60
59
|
#
|
|
61
60
|
# @param event [Contrast::Api::Dtm, Contrast::Api::Dtm::Poll] One of the DTMs valid for the event field of
|
|
62
|
-
# Contrast::Api::Dtm::Message
|
|
61
|
+
# Contrast::Api::Dtm::Message
|
|
63
62
|
# @param force [Boolean] if we should always queue this event, even if the service isn't running, in case the
|
|
64
63
|
# message may be ready before the service has initiated. usually for those events which happen in a separate
|
|
65
64
|
# thread or which may occur during initialization.
|
|
@@ -53,13 +53,13 @@ module Contrast
|
|
|
53
53
|
# Log information about the connection being used to communicate between the Agent and SpeedRacer.
|
|
54
54
|
def log_connection
|
|
55
55
|
# The socket is set,
|
|
56
|
-
if ::Contrast::CONFIG.
|
|
56
|
+
if ::Contrast::CONFIG.agent.service.socket
|
|
57
57
|
logger.info('Connecting to the Contrast Service using a UnixSocket socket',
|
|
58
58
|
socket: ::Contrast::CONTRAST_SERVICE.socket_path)
|
|
59
59
|
return
|
|
60
60
|
end
|
|
61
61
|
# The host & port are set,
|
|
62
|
-
if ::Contrast::CONFIG.
|
|
62
|
+
if ::Contrast::CONFIG.agent.service.host && ::Contrast::CONFIG.agent.service.port
|
|
63
63
|
logger.info('Connecting to the Contrast Service using a TCP socket',
|
|
64
64
|
host: ::Contrast::CONTRAST_SERVICE.host,
|
|
65
65
|
port: ::Contrast::CONTRAST_SERVICE.port)
|
|
@@ -78,11 +78,11 @@ module Contrast
|
|
|
78
78
|
#
|
|
79
79
|
# @return [String]
|
|
80
80
|
def log_connection_error_msg
|
|
81
|
-
if ::Contrast::CONFIG.
|
|
81
|
+
if ::Contrast::CONFIG.agent.service.host
|
|
82
82
|
'Missing a required connection value to the Contrast Service. ' \
|
|
83
83
|
'`agent.service.port` is not set. ' \
|
|
84
84
|
'Falling back to default TCP socket port.'
|
|
85
|
-
elsif ::Contrast::CONFIG.
|
|
85
|
+
elsif ::Contrast::CONFIG.agent.service.port
|
|
86
86
|
'Missing a required connection value to the Contrast Service. ' \
|
|
87
87
|
'`agent.service.host` is not set. ' \
|
|
88
88
|
'Falling back to default TCP socket host.'
|
|
@@ -55,8 +55,7 @@ module Contrast
|
|
|
55
55
|
# if anything's changed in TeamServer meaning the Agent needs to replace its current settings or there is
|
|
56
56
|
# Protect analysis information or nil if the current Agent settings do not need updating.
|
|
57
57
|
#
|
|
58
|
-
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of
|
|
59
|
-
# Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
|
|
58
|
+
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of Contrast::Api::Dtm::Message
|
|
60
59
|
# @return [Contrast::Api::Settings::AgentSettings,nil]
|
|
61
60
|
def return_response event
|
|
62
61
|
send_to_speedracer(event) do |response|
|
|
@@ -67,8 +66,7 @@ module Contrast
|
|
|
67
66
|
# Send the given Event to SpeedRacer and pass the result to our Contrast::Api::Communication::ResponseProcessor
|
|
68
67
|
# as there is no immediate action required from sending this Event.
|
|
69
68
|
#
|
|
70
|
-
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of
|
|
71
|
-
# Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
|
|
69
|
+
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of Contrast::Api::Dtm::Message
|
|
72
70
|
def process_internally event
|
|
73
71
|
send_to_speedracer(event) do |response|
|
|
74
72
|
response_processor.process(response)
|
|
@@ -80,8 +78,7 @@ module Contrast
|
|
|
80
78
|
# Ensure there is a running SpeedRacer and then send the given Event to it. It is necessary to ensure the
|
|
81
79
|
# SpeedRacer is running as, if the process has crashed or restarted, we must rebuild our context there.
|
|
82
80
|
#
|
|
83
|
-
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of
|
|
84
|
-
# Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
|
|
81
|
+
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of Contrast::Api::Dtm::Message
|
|
85
82
|
# @return [Contrast::Api::Settings::AgentSettings, nil]
|
|
86
83
|
def send_to_speedracer event
|
|
87
84
|
ensure_startup!
|
|
@@ -131,8 +128,7 @@ module Contrast
|
|
|
131
128
|
|
|
132
129
|
# Log the startup message we're sending to SpeedRacer
|
|
133
130
|
#
|
|
134
|
-
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of
|
|
135
|
-
# Contrast::Api::Dtm::Message|Contrast::Api::Dtm::Activity
|
|
131
|
+
# @param event [Contrast::Api::Dtm] One of the DTMs valid for the event field of Contrast::Api::Dtm::Message
|
|
136
132
|
def log_send_event event
|
|
137
133
|
logger.debug('Immediately sending event.', event_id: event.__id__, event_type: event.cs__class.cs__name)
|
|
138
134
|
end
|
|
@@ -41,12 +41,11 @@ module Contrast
|
|
|
41
41
|
#
|
|
42
42
|
# @param msg [Contrast::Api::Dtm::AgentStartup]
|
|
43
43
|
def config! msg
|
|
44
|
-
msg.version = Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.
|
|
45
|
-
msg.server_tags = Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.
|
|
46
|
-
msg.library_tags = Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.
|
|
47
|
-
msg.environment = Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.
|
|
48
|
-
msg.application_tags =
|
|
49
|
-
Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.root.application.tags)
|
|
44
|
+
msg.version = Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.server.version)
|
|
45
|
+
msg.server_tags = Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.server.tags)
|
|
46
|
+
msg.library_tags = Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.inventory.tags)
|
|
47
|
+
msg.environment = Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.server.environment)
|
|
48
|
+
msg.application_tags = Contrast::Utils::StringUtils.protobuf_format(::Contrast::CONFIG.application.tags)
|
|
50
49
|
end
|
|
51
50
|
end
|
|
52
51
|
end
|
|
@@ -31,7 +31,8 @@ module Contrast
|
|
|
31
31
|
{
|
|
32
32
|
modes_by_id: translated_protection_mode_by_id,
|
|
33
33
|
exclusion_matchers: translated_exclusions,
|
|
34
|
-
disabled_assess_rules: disabled_assess_rules
|
|
34
|
+
disabled_assess_rules: disabled_assess_rules,
|
|
35
|
+
session_id: session_id
|
|
35
36
|
}
|
|
36
37
|
end
|
|
37
38
|
end
|