contrast-agent 6.2.0 → 6.3.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_basic_object/cs__assess_basic_object.c +7 -5
- data/ext/cs__assess_kernel/cs__assess_kernel.c +14 -3
- data/ext/cs__assess_kernel/cs__assess_kernel.h +2 -0
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +10 -3
- data/ext/cs__assess_marshal_module/cs__assess_marshal_module.h +2 -1
- data/ext/cs__assess_regexp/cs__assess_regexp.c +9 -7
- data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.c → cs__assess_string_interpolation/cs__assess_string_interpolation.c} +14 -3
- data/ext/{cs__assess_string_interpolation26/cs__assess_string_interpolation26.h → cs__assess_string_interpolation/cs__assess_string_interpolation.h} +1 -1
- data/ext/{cs__assess_string_interpolation26 → cs__assess_string_interpolation}/extconf.rb +0 -0
- data/ext/cs__common/cs__common.c +5 -4
- data/ext/cs__contrast_patch/cs__contrast_patch.c +3 -10
- data/lib/contrast/agent/assess/events/source_event.rb +16 -12
- data/lib/contrast/agent/assess/policy/policy_node.rb +6 -0
- data/lib/contrast/agent/assess/policy/propagation_method.rb +3 -39
- data/lib/contrast/agent/assess/policy/propagation_node.rb +8 -0
- data/lib/contrast/agent/assess/policy/propagator/base.rb +2 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +2 -47
- data/lib/contrast/agent/assess/policy/source_node.rb +1 -0
- data/lib/contrast/agent/assess/policy/trigger_node.rb +8 -0
- data/lib/contrast/agent/assess/property/evented.rb +4 -18
- data/lib/contrast/agent/assess/tag.rb +19 -0
- data/lib/contrast/agent/at_exit_hook.rb +8 -8
- data/lib/contrast/agent/inventory/database_config.rb +6 -3
- data/lib/contrast/agent/inventory/dependency_analysis.rb +3 -2
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +10 -10
- data/lib/contrast/agent/middleware.rb +4 -0
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +27 -2
- data/lib/contrast/agent/patching/policy/policy.rb +5 -0
- data/lib/contrast/agent/patching/policy/policy_node.rb +6 -0
- data/lib/contrast/agent/patching/policy/trigger_node.rb +3 -0
- data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +3 -4
- data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -0
- data/lib/contrast/agent/protect/policy/rule_applicator.rb +2 -2
- data/lib/contrast/agent/protect/rule/base.rb +1 -0
- data/lib/contrast/agent/protect/rule/no_sqli.rb +2 -0
- data/lib/contrast/agent/reporting/reporter.rb +32 -7
- data/lib/contrast/agent/reporting/reporter_heartbeat.rb +21 -15
- data/lib/contrast/agent/reporting/reporting_events/application_update.rb +5 -24
- data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +8 -1
- data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +8 -1
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +7 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +10 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +12 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +11 -1
- data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +29 -32
- data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +13 -1
- data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +11 -8
- data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +12 -5
- data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +8 -1
- data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +9 -1
- data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +10 -1
- data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +11 -4
- data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -8
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +1 -4
- data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +0 -22
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -3
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -11
- data/lib/contrast/agent/request.rb +5 -7
- data/lib/contrast/agent/request_context.rb +8 -17
- data/lib/contrast/agent/request_context_extend.rb +8 -9
- data/lib/contrast/agent/request_handler.rb +9 -38
- data/lib/contrast/agent/rule_set.rb +4 -0
- data/lib/contrast/agent/service_heartbeat.rb +1 -1
- data/lib/contrast/agent/static_analysis.rb +6 -11
- data/lib/contrast/agent/telemetry/base.rb +35 -35
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +2 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +2 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +5 -2
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +3 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +3 -0
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +0 -1
- data/lib/contrast/agent/thread_watcher.rb +1 -4
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/communication/socket.rb +1 -0
- data/lib/contrast/api/decorators/message.rb +0 -6
- data/lib/contrast/api/decorators.rb +0 -2
- data/lib/contrast/components/assess.rb +0 -6
- data/lib/contrast/components/config.rb +18 -2
- data/lib/contrast/config/base_configuration.rb +0 -13
- data/lib/contrast/config/root_configuration.rb +1 -0
- data/lib/contrast/config/ruby_configuration.rb +2 -9
- data/lib/contrast/configuration.rb +0 -2
- data/lib/contrast/extension/assess/eval_trigger.rb +0 -4
- data/lib/contrast/extension/assess/hash.rb +3 -2
- data/lib/contrast/extension/assess/kernel.rb +22 -0
- data/lib/contrast/extension/assess/marshal.rb +16 -0
- data/lib/contrast/extension/assess/string.rb +21 -20
- data/lib/contrast/framework/base_support.rb +8 -0
- data/lib/contrast/framework/manager.rb +6 -20
- data/lib/contrast/framework/manager_extend.rb +0 -1
- data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +11 -16
- data/lib/contrast/logger/aliased_logging.rb +2 -0
- data/lib/contrast/utils/assess/source_method_utils.rb +0 -9
- data/lib/contrast/utils/lru_cache.rb +3 -0
- data/lib/contrast/utils/middleware_utils.rb +2 -0
- data/lib/contrast/utils/telemetry_client.rb +7 -7
- data/resources/assess/policy.json +2 -11
- data/ruby-agent.gemspec +1 -1
- metadata +22 -20
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +0 -30
- data/lib/contrast/api/decorators/application_update.rb +0 -44
- data/lib/contrast/api/decorators/library.rb +0 -56
- data/lib/contrast/framework/platform_version.rb +0 -22
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
require 'contrast/api/dtm.pb'
|
|
5
5
|
require 'contrast/utils/string_utils'
|
|
6
|
+
require 'contrast/components/logger'
|
|
6
7
|
|
|
7
8
|
module Contrast
|
|
8
9
|
module Agent
|
|
@@ -16,6 +17,8 @@ module Contrast
|
|
|
16
17
|
# @attr_reader verb [String] the HTTP Method requested to his this endpoint. Empty means all, so is allowed.
|
|
17
18
|
# for reporting.
|
|
18
19
|
class RouteDiscoveryObservation
|
|
20
|
+
include Contrast::Components::Logger::InstanceMethods
|
|
21
|
+
|
|
19
22
|
# required attributes
|
|
20
23
|
attr_reader :url
|
|
21
24
|
# optional attributes
|
|
@@ -47,10 +50,14 @@ module Contrast
|
|
|
47
50
|
# @return [Hash]
|
|
48
51
|
# @raise [ArgumentError]
|
|
49
52
|
def to_controlled_hash
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
begin
|
|
54
|
+
validate
|
|
55
|
+
rescue ArgumentError => e
|
|
56
|
+
logger.error('RouteDiscoveryObservation validation failed with: ', e)
|
|
57
|
+
return
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
{ url: url, verb: verb }.compact
|
|
54
61
|
end
|
|
55
62
|
|
|
56
63
|
# Ensure the required fields are present.
|
|
@@ -12,14 +12,6 @@ module Contrast
|
|
|
12
12
|
# for its response, which contains any updated server feature settings from TeamServer. The new Server Settings
|
|
13
13
|
# endpoint should let us remove this.
|
|
14
14
|
class ServerActivity < Contrast::Agent::Reporting::ServerReportingEvent
|
|
15
|
-
class << self
|
|
16
|
-
# @param _server_activity_dtm [Contrast::Api::Dtm::ServerActivity]
|
|
17
|
-
# @return [Contrast::Agent::Reporting::ServerActivity]
|
|
18
|
-
def convert _server_activity_dtm
|
|
19
|
-
new
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
15
|
def initialize
|
|
24
16
|
@event_method = :PUT
|
|
25
17
|
@event_endpoint = "#{ Contrast::API.api_url }/api/ng/activity/server"
|
|
@@ -44,10 +44,7 @@ module Contrast
|
|
|
44
44
|
# @param file_name[String] file_name to log
|
|
45
45
|
# @param data[String] String representation if the logged data
|
|
46
46
|
def log_data type, file_name, data = nil
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
logger.debug('logging to file', file_name: file_name) # TODO: RUBY-99999 DO NOT COMMIT THIS
|
|
50
|
-
write_to_file(type, file_name, data)
|
|
47
|
+
write_to_file(type, file_name, data) if enabled?
|
|
51
48
|
end
|
|
52
49
|
|
|
53
50
|
# This method will be actually writing to the file
|
|
@@ -1,7 +1,6 @@
|
|
|
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/server_activity'
|
|
5
4
|
require 'contrast/agent/reporting/reporting_events/application_activity'
|
|
6
5
|
require 'contrast/api/dtm.pb'
|
|
7
6
|
|
|
@@ -13,22 +12,6 @@ module Contrast
|
|
|
13
12
|
# TODO: RUBY-1438 -- remove
|
|
14
13
|
module DtmMessage
|
|
15
14
|
class << self
|
|
16
|
-
# Checks if the message is of Contrast::Api::Dtm::ServerActivity class
|
|
17
|
-
#
|
|
18
|
-
# @param dtm [Contrast::Api::Dtm::ServerActivity, Object]
|
|
19
|
-
# @return [Boolean]
|
|
20
|
-
def server_activity? dtm
|
|
21
|
-
dtm.cs__is_a?(Contrast::Api::Dtm::ServerActivity)
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
# Checks if the message is of Contrast::Api::Dtm::ApplicationUpdate class
|
|
25
|
-
#
|
|
26
|
-
# @param dtm [Contrast::Api::Dtm::ApplicationUpdate,Object]
|
|
27
|
-
# @return [Boolean]
|
|
28
|
-
def application_update? dtm
|
|
29
|
-
dtm.cs__is_a?(Contrast::Api::Dtm::ApplicationUpdate)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
15
|
# @param dtm [Contrast::Api::Dtm::Finding,Object]
|
|
33
16
|
# @return [Boolean]
|
|
34
17
|
def finding? dtm
|
|
@@ -47,12 +30,7 @@ module Contrast
|
|
|
47
30
|
# @param dtm [Contrast::Api::Dtm]
|
|
48
31
|
# @return event [Contrast::Agent::Reporting::ReportingEvent, nil]
|
|
49
32
|
def dtm_to_event dtm
|
|
50
|
-
# For the ServerActivity we need to create and send empty body only. This is done because we need the
|
|
51
|
-
# response from TS.
|
|
52
|
-
return Contrast::Agent::Reporting::ServerActivity.new if server_activity?(dtm)
|
|
53
|
-
|
|
54
33
|
# For the others, we convert them.
|
|
55
|
-
return Contrast::Agent::Reporting::ApplicationUpdate.convert(dtm) if application_update?(dtm)
|
|
56
34
|
return Contrast::Agent::Reporting::Finding.convert(dtm) if finding?(dtm)
|
|
57
35
|
return Contrast::Agent::Reporting::ApplicationActivity.convert(dtm) if activity?(dtm)
|
|
58
36
|
|
|
@@ -53,12 +53,10 @@ module Contrast
|
|
|
53
53
|
# @param event [Contrast::Agent::Reporting::ReportingEvent] The event to send to TeamServer. Really a
|
|
54
54
|
# child of the ReportingEvent rather than a literal one.
|
|
55
55
|
# @param connection [Net::HTTP] open connection
|
|
56
|
-
# @param send_immediately [Boolean] flag for the logger
|
|
57
56
|
# @return response [Net::HTTP::Response, nil] response from TS if no response
|
|
58
|
-
def send_event event, connection
|
|
57
|
+
def send_event event, connection
|
|
59
58
|
return unless connection
|
|
60
59
|
|
|
61
|
-
log_send_event(event) if send_immediately
|
|
62
60
|
request = build_request(event)
|
|
63
61
|
response = connection.request(request)
|
|
64
62
|
audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable?
|
|
@@ -39,7 +39,7 @@ module Contrast
|
|
|
39
39
|
|
|
40
40
|
STARTUP_EVENTS.each do |event|
|
|
41
41
|
startup_event = event.new
|
|
42
|
-
send_event(startup_event, connection
|
|
42
|
+
send_event(startup_event, connection)
|
|
43
43
|
rescue StandardError => e
|
|
44
44
|
handle_error(startup_event, e)
|
|
45
45
|
end
|
|
@@ -66,15 +66,6 @@ module Contrast
|
|
|
66
66
|
request
|
|
67
67
|
end
|
|
68
68
|
|
|
69
|
-
# log the event sent immediately
|
|
70
|
-
#
|
|
71
|
-
# @param event [Contrast::Agent::Reporting::ReportingEvent] The event to send to TeamServer. Really a
|
|
72
|
-
# child of the ReportingEvent rather than a literal one.
|
|
73
|
-
def log_send_event event
|
|
74
|
-
logger.debug("#{ Contrast::Agent::Reporting::ReporterClient::SERVICE_NAME } immediately sending event.",
|
|
75
|
-
event_id: event.__id__, event_type: event.cs__class.cs__name)
|
|
76
|
-
end
|
|
77
|
-
|
|
78
69
|
# Handles standard error case, logs and set status for failure
|
|
79
70
|
#
|
|
80
71
|
# @param event [Contrast::Agent::Reporting::ReportingEvent]
|
|
@@ -96,7 +87,6 @@ module Contrast
|
|
|
96
87
|
# @param response [Net::HTTP::Response]
|
|
97
88
|
def process_settings_response response
|
|
98
89
|
response_handler.process(response)
|
|
99
|
-
logger.debug('Successfully sent startup messages to TeamServer.')
|
|
100
90
|
status.success!
|
|
101
91
|
end
|
|
102
92
|
|
|
@@ -17,12 +17,6 @@ module Contrast
|
|
|
17
17
|
# provides access to the original Rack::Request object as well as extracts
|
|
18
18
|
# data in a format that the Agent expects, caching those transformations in
|
|
19
19
|
# order to avoid repeatedly creating Strings & thrashing GC.
|
|
20
|
-
#
|
|
21
|
-
# @attr_reader rack_request [Rack::Request] The passed to the Agent RackRequest to be wrapped.
|
|
22
|
-
# @attr_accessor route [Contrast::Api::Dtm::RouteCoverage] the route, used for findings, of this request
|
|
23
|
-
# @attr_accessor observed_route [Contrast::Api::Dtm::ObservedRoute] the route, used for coverage of this request
|
|
24
|
-
# @attr_accessor new_observed_route [Contrast::Agent::Reporting::ObservedRoute] the route, used for coverage, of
|
|
25
|
-
# this request
|
|
26
20
|
class Request
|
|
27
21
|
include Contrast::Utils::RequestUtils
|
|
28
22
|
include Contrast::Components::Logger::InstanceMethods
|
|
@@ -37,8 +31,12 @@ module Contrast
|
|
|
37
31
|
STATIC_SUFFIXES = /\.(?:js|css|jpeg|jpg|gif|png|ico|woff|svg|pdf|eot|ttf|jar)$/i.cs__freeze
|
|
38
32
|
MEDIA_TYPE_MARKERS = %w[image/ text/css text/javascript].cs__freeze
|
|
39
33
|
|
|
34
|
+
# @return [Rack::Request] The passed to the Agent RackRequest to be wrapped.
|
|
40
35
|
attr_reader :rack_request
|
|
41
|
-
|
|
36
|
+
# @return [Contrast::Api::Dtm::RouteCoverage] the route, used for findings, of this request
|
|
37
|
+
attr_accessor :route
|
|
38
|
+
# @return [Contrast::Agent::Reporting::ObservedRoute] the route, used for coverage, of this request
|
|
39
|
+
attr_accessor :observed_route
|
|
42
40
|
|
|
43
41
|
# Delegate calls to the following methods to the attribute @rack_request
|
|
44
42
|
def_delegators :@rack_request, :base_url, :cookies, :env, :ip, :media_type, :path, :port, :query_string,
|
|
@@ -30,8 +30,6 @@ module Contrast
|
|
|
30
30
|
# @return [Hash] context used to log the request
|
|
31
31
|
attr_reader :logging_hash
|
|
32
32
|
# @return [Contrast::Agent::Reporting::ObservedRoute] the route, used for coverage, of this request
|
|
33
|
-
attr_reader :new_observed_route
|
|
34
|
-
# @return [Contrast::Api::Dtm::ObservedRoute] the route, used for coverage, of this request
|
|
35
33
|
attr_reader :observed_route
|
|
36
34
|
# @return [Contrast::Agent::Request] our wrapper around the Rack::Request for this context
|
|
37
35
|
attr_reader :request
|
|
@@ -40,15 +38,10 @@ module Contrast
|
|
|
40
38
|
attr_reader :response
|
|
41
39
|
# @return [Contrast::Api::Dtm::RouteCoverage] the route, used for findings, of this request
|
|
42
40
|
attr_reader :route
|
|
43
|
-
# @return [Contrast::Api::Dtm::ServerActivity] the server activity found in this request
|
|
44
|
-
attr_reader :server_activity
|
|
45
41
|
# @return [Contrast::Api::Settings::InputAnalysis] the protect input analysis of sources on this request
|
|
46
42
|
attr_reader :speedracer_input_analysis
|
|
47
43
|
# @return [Contrast::Utils::Timer] when the context was created
|
|
48
44
|
attr_reader :timer
|
|
49
|
-
# @return [Contrast::Agent::Reporting::ObservedLibraryUsage] List of the libraries that have been observed to be
|
|
50
|
-
# executed or to have something loaded. This here replaces part of the Activity Dtm
|
|
51
|
-
attr_reader :observed_library_usage
|
|
52
45
|
|
|
53
46
|
def initialize rack_request, app_loaded: true
|
|
54
47
|
with_contrast_scope do
|
|
@@ -62,9 +55,6 @@ module Contrast
|
|
|
62
55
|
@activity = Contrast::Api::Dtm::Activity.new
|
|
63
56
|
@activity.http_request = request.dtm
|
|
64
57
|
|
|
65
|
-
@server_activity = Contrast::Api::Dtm::ServerActivity.new
|
|
66
|
-
@observed_library_usage = Contrast::Agent::Reporting::ObservedLibraryUsage.new
|
|
67
|
-
|
|
68
58
|
# build analyzer
|
|
69
59
|
@do_not_track = false
|
|
70
60
|
@speedracer_input_analysis = EMPTY_INPUT_ANALYSIS_PB
|
|
@@ -128,20 +118,21 @@ module Contrast
|
|
|
128
118
|
|
|
129
119
|
def reset_activity
|
|
130
120
|
@activity = Contrast::Api::Dtm::Activity.new(http_request: request.dtm)
|
|
131
|
-
@
|
|
132
|
-
@observed_route = Contrast::Api::Dtm::ObservedRoute.new # TODO: RUBY-1438 -- remove
|
|
133
|
-
@new_observed_route = Contrast::Agent::Reporting::ObservedRoute.new
|
|
121
|
+
@observed_route = Contrast::Agent::Reporting::ObservedRoute.new
|
|
134
122
|
end
|
|
135
123
|
|
|
136
124
|
private
|
|
137
125
|
|
|
138
126
|
def handle_routes
|
|
139
|
-
@observed_route = Contrast::
|
|
140
|
-
|
|
127
|
+
@observed_route = Contrast::Agent::Reporting::ObservedRoute.new
|
|
128
|
+
# TODO: RUBY-1705 when we no longer need the DTM style, delete this method and use the get_route_information
|
|
129
|
+
# instead.
|
|
141
130
|
route_dtm = Contrast::Agent.framework_manager.get_route_dtm(@request)
|
|
142
|
-
new_route_coverage_dtm = Contrast::Agent.framework_manager.get_route_information(@request)
|
|
131
|
+
# new_route_coverage_dtm = Contrast::Agent.framework_manager.get_route_information(@request)
|
|
132
|
+
# TODO: RUBY-1705 -- delete append_route_coverage
|
|
143
133
|
append_route_coverage(route_dtm)
|
|
144
|
-
|
|
134
|
+
# TODO: RUBY-1705 -- change to take [Contrast::Agent::Reporting::ObservedRoute]
|
|
135
|
+
append_to_observed_route(route_dtm)
|
|
145
136
|
end
|
|
146
137
|
end
|
|
147
138
|
end
|
|
@@ -38,23 +38,20 @@ module Contrast
|
|
|
38
38
|
@activity.routes << route
|
|
39
39
|
|
|
40
40
|
# For TS routes
|
|
41
|
-
@observed_route.signature = route.route
|
|
42
|
-
@observed_route.verb = route.verb
|
|
43
|
-
@observed_route.url = route.url if route.url
|
|
44
41
|
@request.route = route
|
|
45
|
-
@request.observed_route = @observed_route
|
|
46
42
|
end
|
|
47
43
|
|
|
48
44
|
# Convert the discovered route for this request to appropriate forms and disseminate it to those locations
|
|
49
45
|
# where it is necessary for our route coverage and finding vulnerability discovery features to function.
|
|
50
46
|
#
|
|
51
|
-
|
|
47
|
+
# @param route [Contrast::Api::Dtm::RouteCoverage]
|
|
48
|
+
def append_to_observed_route route
|
|
52
49
|
return unless route
|
|
53
50
|
|
|
54
|
-
@
|
|
55
|
-
@
|
|
56
|
-
@
|
|
57
|
-
@request.
|
|
51
|
+
@observed_route.signature = route.route
|
|
52
|
+
@observed_route.verb = route.verb
|
|
53
|
+
@observed_route.url = route.url if route.url
|
|
54
|
+
@request.observed_route = @observed_route
|
|
58
55
|
end
|
|
59
56
|
|
|
60
57
|
# Collect the results for the given rule with the given action
|
|
@@ -71,6 +68,7 @@ module Contrast
|
|
|
71
68
|
end
|
|
72
69
|
end
|
|
73
70
|
|
|
71
|
+
# @raise [Contrast::SecurityException]
|
|
74
72
|
def service_extract_request
|
|
75
73
|
return false unless ::Contrast::AGENT.enabled?
|
|
76
74
|
return false unless ::Contrast::PROTECT.enabled?
|
|
@@ -105,6 +103,7 @@ module Contrast
|
|
|
105
103
|
# Normally these should be generated on Speedracer for any attacks detected during prefilter.
|
|
106
104
|
#
|
|
107
105
|
# @param agent_settings [Contrast::Api::Settings::AgentSettings]
|
|
106
|
+
# @raise[Contrast::SecurityException]
|
|
108
107
|
def handle_protect_state agent_settings
|
|
109
108
|
return unless agent_settings&.protect_state
|
|
110
109
|
|
|
@@ -22,56 +22,27 @@ module Contrast
|
|
|
22
22
|
@ruleset = ::Contrast::AGENT.ruleset
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
# Send Activities messages to TS [Contrast::
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# Contrast::Api::Dtm::ObservedRoute]
|
|
29
|
-
# If bypass is enabled use the reporting service if not than the messages are
|
|
30
|
-
# send with speedracer
|
|
31
|
-
# TODO: RUBY-1355
|
|
32
|
-
# TODO: RUBY-1358
|
|
33
|
-
# TODO: RUBY-1438 -- remove
|
|
25
|
+
# Send Activities messages to TS [Contrast::Api::Dtm::Activity]
|
|
26
|
+
# TODO: RUBY-1704
|
|
27
|
+
# TODO: RUBY-1438
|
|
34
28
|
def send_activity_messages
|
|
35
|
-
|
|
36
|
-
unless Contrast::Agent::Reporter.enabled?
|
|
37
|
-
events << context.server_activity
|
|
38
|
-
events << context.observed_route
|
|
39
|
-
end
|
|
40
|
-
events.each do |message|
|
|
41
|
-
Contrast::Agent.messaging_queue&.send_event_eventually(message)
|
|
42
|
-
end
|
|
29
|
+
Contrast::Agent.messaging_queue&.send_event_eventually(context.activity)
|
|
43
30
|
end
|
|
44
31
|
|
|
45
32
|
# reports events[Contrast::Agent::Reporting::ReporterEvent] to TS
|
|
46
33
|
# This method is used to send our JSON messages directly to TeamServer at the end of each request. As we move
|
|
47
34
|
# more endpoints over, this method will take the messages originally sent by #send_actiivty_messages. At the end,
|
|
48
35
|
# that method should be removed.
|
|
49
|
-
def report_activity
|
|
50
|
-
Contrast::Agent
|
|
51
|
-
generate_library_usage(context.observed_library_usage)
|
|
36
|
+
def report_activity
|
|
37
|
+
return unless (reporter = Contrast::Agent.reporter)
|
|
52
38
|
|
|
53
|
-
|
|
39
|
+
reporter.send_event(context.observed_route)
|
|
54
40
|
return unless Contrast::Agent::Reporter.enabled?
|
|
55
41
|
|
|
56
|
-
reporter = Contrast::Agent.reporter
|
|
57
|
-
return unless reporter
|
|
58
|
-
|
|
59
42
|
# Mask Sensitive Data
|
|
60
43
|
Contrast::Agent::Reporting::Masker.mask(context.activity)
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
generate_library_usage(context.observed_library_usage)
|
|
64
|
-
[
|
|
65
|
-
context.new_observed_route,
|
|
66
|
-
context.observed_library_usage,
|
|
67
|
-
Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.server_activity),
|
|
68
|
-
Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.activity)
|
|
69
|
-
].each do |event|
|
|
70
|
-
reporter.send_event(event)
|
|
71
|
-
rescue StandardError => e
|
|
72
|
-
logger.warn('Unable to send Event Activity', e)
|
|
73
|
-
end
|
|
74
|
-
context.observed_library_usage.clear # TODO: RUBY-1355 remove when no longer using activity
|
|
44
|
+
event = Contrast::Agent::Reporting::DtmMessage.dtm_to_event(context.activity)
|
|
45
|
+
reporter.send_event(event)
|
|
75
46
|
end
|
|
76
47
|
|
|
77
48
|
# If the response is streaming, we should only perform filtering on our stream safe rules
|
|
@@ -14,6 +14,8 @@ module Contrast
|
|
|
14
14
|
# The main action here is snapshotting the request as provided to the application from the
|
|
15
15
|
# user before any application code has acted upon it. Additionally, this is where Protect will
|
|
16
16
|
# terminate requests on attack detection if set to block at perimeter
|
|
17
|
+
#
|
|
18
|
+
# @raise [Contrast::SecurityException] raises error if security exception is thrown in prefilter
|
|
17
19
|
def prefilter
|
|
18
20
|
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
19
21
|
return unless context&.analyze_request?
|
|
@@ -30,6 +32,8 @@ module Contrast
|
|
|
30
32
|
|
|
31
33
|
# The filtering that needs occur after the application has acted on the request and the response
|
|
32
34
|
# has been created. The main actions here are analyzing the response for unsafe state or actions.
|
|
35
|
+
#
|
|
36
|
+
# @raise [Contrast::SecurityException] raises error if security exception is thrown in postfilter
|
|
33
37
|
def postfilter
|
|
34
38
|
context = Contrast::Agent::REQUEST_TRACKER.current
|
|
35
39
|
return unless context&.analyze_response?
|
|
@@ -22,7 +22,7 @@ module Contrast
|
|
|
22
22
|
@_thread = Contrast::Agent::Thread.new do
|
|
23
23
|
logger.info('Starting heartbeat thread.')
|
|
24
24
|
loop do
|
|
25
|
-
Contrast::Agent.messaging_queue
|
|
25
|
+
Contrast::Agent.messaging_queue&.send_event_eventually(poll_message)
|
|
26
26
|
sleep(REFRESH_INTERVAL_SEC)
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
require 'contrast/components/logger'
|
|
5
5
|
require 'contrast/components/scope'
|
|
6
6
|
require 'contrast/agent/reporting/reporting_events/application_update'
|
|
7
|
-
require 'contrast/api/decorators/application_update'
|
|
8
7
|
|
|
9
8
|
module Contrast
|
|
10
9
|
module Agent
|
|
@@ -24,20 +23,16 @@ module Contrast
|
|
|
24
23
|
end
|
|
25
24
|
end
|
|
26
25
|
|
|
27
|
-
# TODO: RUBY-1703
|
|
28
26
|
def send_inventory_message
|
|
29
27
|
return unless ::Contrast::INVENTORY.enabled?
|
|
30
28
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Contrast::Agent.reporter.send_event(
|
|
37
|
-
else
|
|
38
|
-
Contrast::Agent.messaging_queue.send_event_eventually(app_update_msg, force: true)
|
|
29
|
+
report = Contrast::Agent::Reporting::ApplicationUpdate.new
|
|
30
|
+
# This convert here is left as it'll be easier to be replaced when the Library is being changed
|
|
31
|
+
report.libraries = Contrast::Agent::Inventory::DependencyAnalysis.instance.library_pb_list
|
|
32
|
+
Contrast::Agent::Inventory::DatabaseConfig.append_db_config(report)
|
|
33
|
+
[report, Contrast::Agent::Reporting::ApplicationInventory.new].each do |e|
|
|
34
|
+
Contrast::Agent.reporter.send_event(e)
|
|
39
35
|
end
|
|
40
|
-
Contrast::Agent.reporter.send_event(Contrast::Agent::Reporting::ApplicationInventory.new)
|
|
41
36
|
end
|
|
42
37
|
|
|
43
38
|
private
|
|
@@ -7,7 +7,6 @@ require 'contrast/utils/telemetry_client'
|
|
|
7
7
|
require 'contrast/agent/worker_thread'
|
|
8
8
|
require 'contrast/utils/telemetry'
|
|
9
9
|
require 'contrast/agent/telemetry/events/exceptions/telemetry_exceptions'
|
|
10
|
-
require 'contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report'
|
|
11
10
|
|
|
12
11
|
module Contrast
|
|
13
12
|
module Agent
|
|
@@ -15,7 +14,6 @@ module Contrast
|
|
|
15
14
|
# This class will initialize and hold everything needed for the telemetry
|
|
16
15
|
class Base < WorkerThread
|
|
17
16
|
include Contrast::Components::Logger::InstanceMethods
|
|
18
|
-
include Contrast::Agent::Telemetry::TelemetryExceptionReport
|
|
19
17
|
|
|
20
18
|
# this is where we will send the data from the agents
|
|
21
19
|
URL = 'https://telemetry.ruby.contrastsecurity.com/'
|
|
@@ -66,10 +64,6 @@ module Contrast
|
|
|
66
64
|
@_connection ||= client.initialize_connection(URL)
|
|
67
65
|
end
|
|
68
66
|
|
|
69
|
-
def error_messages
|
|
70
|
-
@_error_messages ||= []
|
|
71
|
-
end
|
|
72
|
-
|
|
73
67
|
def attempt_to_start?
|
|
74
68
|
unless cs__class.enabled?
|
|
75
69
|
logger.warn('Telemetry service is disabled!')
|
|
@@ -83,34 +77,8 @@ module Contrast
|
|
|
83
77
|
def start_thread!
|
|
84
78
|
return if running?
|
|
85
79
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
@_thread = Contrast::Agent::Thread.new do
|
|
89
|
-
logger.debug('Starting background telemetry thread.')
|
|
90
|
-
loop do
|
|
91
|
-
next unless client && connection
|
|
92
|
-
|
|
93
|
-
# Start pushing exceptions to queue for reporting.
|
|
94
|
-
push_exceptions
|
|
95
|
-
until queue.empty?
|
|
96
|
-
event = queue.pop
|
|
97
|
-
begin
|
|
98
|
-
logger.debug('This is the current processed event', event)
|
|
99
|
-
sleep_time = request_with_response(event)
|
|
100
|
-
if sleep_time
|
|
101
|
-
sleep(sleep_time)
|
|
102
|
-
logger.debug('Retrying to process event', event)
|
|
103
|
-
retry_sleep_time = request_with_response(event)
|
|
104
|
-
sleep(retry_sleep_time) unless retry_sleep_time.nil?
|
|
105
|
-
end
|
|
106
|
-
rescue StandardError => e
|
|
107
|
-
logger.error('Could not send message to service from telemetry queue.', e)
|
|
108
|
-
stop!
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
sleep(SUGGESTED_TIMEOUT)
|
|
112
|
-
end
|
|
113
|
-
end
|
|
80
|
+
logger.debug('Starting background telemetry thread.')
|
|
81
|
+
@_thread = create_thread
|
|
114
82
|
end
|
|
115
83
|
|
|
116
84
|
def send_event event
|
|
@@ -126,7 +94,6 @@ module Contrast
|
|
|
126
94
|
end
|
|
127
95
|
|
|
128
96
|
def delete_queue!
|
|
129
|
-
@_queue&.clear
|
|
130
97
|
@_queue&.close
|
|
131
98
|
@_queue = nil
|
|
132
99
|
end
|
|
@@ -149,6 +116,39 @@ module Contrast
|
|
|
149
116
|
def queue
|
|
150
117
|
@_queue ||= Queue.new
|
|
151
118
|
end
|
|
119
|
+
|
|
120
|
+
# It is recommended that implementations send a single payload of general metrics every 3 hours, starting from
|
|
121
|
+
# implementation startup. This returns a thread configured to do so.
|
|
122
|
+
#
|
|
123
|
+
# @return [Contrast::Agent::Thread]
|
|
124
|
+
def create_thread
|
|
125
|
+
Contrast::Agent::Thread.new do
|
|
126
|
+
loop do
|
|
127
|
+
next unless client && connection
|
|
128
|
+
|
|
129
|
+
# Start pushing exceptions to queue for reporting.
|
|
130
|
+
Contrast::TELEMETRY_EXCEPTIONS.each_value { |value| queue << value }
|
|
131
|
+
Contrast::TELEMETRY_EXCEPTIONS.clear
|
|
132
|
+
until queue.empty?
|
|
133
|
+
event = queue.pop
|
|
134
|
+
begin
|
|
135
|
+
logger.debug('This is the current processed event', event)
|
|
136
|
+
sleep_time = request_with_response(event)
|
|
137
|
+
if sleep_time
|
|
138
|
+
sleep(sleep_time)
|
|
139
|
+
logger.debug('Retrying to process event', event)
|
|
140
|
+
retry_sleep_time = request_with_response(event)
|
|
141
|
+
sleep(retry_sleep_time) unless retry_sleep_time.nil?
|
|
142
|
+
end
|
|
143
|
+
rescue StandardError => e
|
|
144
|
+
logger.error('Could not send message to service from telemetry queue.', e)
|
|
145
|
+
stop!
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
sleep(SUGGESTED_TIMEOUT)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
152
|
end
|
|
153
153
|
end
|
|
154
154
|
end
|
|
@@ -28,6 +28,7 @@ module Contrast
|
|
|
28
28
|
#
|
|
29
29
|
# @param validation_pair [Hash] Validation hash to use
|
|
30
30
|
# @param key[String] The key to check in VALIDATIONS
|
|
31
|
+
# @raise [ArgumentError]
|
|
31
32
|
def validate_field validation_pair, key
|
|
32
33
|
value_to_validate = send(key.to_sym)
|
|
33
34
|
validate_class(value_to_validate, validation_pair[:class], key) if validation_pair.key?(:class)
|
|
@@ -48,6 +49,7 @@ module Contrast
|
|
|
48
49
|
# @param message [Object] The message we want to check the class of
|
|
49
50
|
# @param klass [Class] The klass we want to check the message with
|
|
50
51
|
# @param field [Object] The field with the error
|
|
52
|
+
# @raise [ArgumentError]
|
|
51
53
|
def validate_class message, klass, field
|
|
52
54
|
message = message[0] if message.cs__is_a?(Array)
|
|
53
55
|
raise(ArgumentError, "The provided value for #{ field } is of wrong class") unless message.cs__is_a?(klass)
|
|
@@ -18,6 +18,7 @@ module Contrast
|
|
|
18
18
|
# to be created
|
|
19
19
|
#
|
|
20
20
|
# @param message [Contrast::Agent::Telemetry::TelemetryException::Message]
|
|
21
|
+
# @raise[ArgumentError]
|
|
21
22
|
def initialize message
|
|
22
23
|
super()
|
|
23
24
|
validate_class(message, Contrast::Agent::Telemetry::TelemetryException::Message, 'exception_message')
|
|
@@ -25,6 +26,7 @@ module Contrast
|
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
# @param message [Contrast::Agent::Telemetry::TelemetryException::Message]
|
|
29
|
+
# @raise[ArgumentError]
|
|
28
30
|
def push message
|
|
29
31
|
validate_class(message, Contrast::Agent::Telemetry::TelemetryException::Message, 'exception_message')
|
|
30
32
|
@exceptions << message
|
|
@@ -50,6 +50,7 @@ module Contrast
|
|
|
50
50
|
# @return [String | nil] A string message to provide additional context to the errors.
|
|
51
51
|
attr_reader :message
|
|
52
52
|
|
|
53
|
+
# @raise[ArgumentError]
|
|
53
54
|
def initialize instance, tags, exceptions
|
|
54
55
|
super()
|
|
55
56
|
@tags = tags
|
|
@@ -63,17 +64,19 @@ module Contrast
|
|
|
63
64
|
# Optional parameters will be set separately from the required
|
|
64
65
|
#
|
|
65
66
|
# @param logger[String]
|
|
67
|
+
# @raise[ArgumentError]
|
|
66
68
|
def logger= logger
|
|
67
|
-
validate_field(VALIDATIONS[:logger], 'logger')
|
|
68
69
|
@logger = logger
|
|
70
|
+
validate_field(VALIDATIONS[:logger], 'logger')
|
|
69
71
|
end
|
|
70
72
|
|
|
71
73
|
# Optional parameters will be set separately from the required
|
|
72
74
|
#
|
|
73
75
|
# @param message[String]
|
|
76
|
+
# @raise[ArgumentError]
|
|
74
77
|
def message= message
|
|
75
|
-
validate_field(VALIDATIONS[:message], 'message')
|
|
76
78
|
@message = message
|
|
79
|
+
validate_field(VALIDATIONS[:message], 'message')
|
|
77
80
|
end
|
|
78
81
|
|
|
79
82
|
# Optional parameters will be set separately from the required
|
data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb
CHANGED
|
@@ -43,16 +43,19 @@ module Contrast
|
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
# @param stack_frame [Contrast::Agent::Telemetry::TelemetryException::StackFrame]
|
|
46
|
+
# @raise[ArgumentError]
|
|
46
47
|
def push stack_frame
|
|
47
48
|
validate_class(stack_frame, Contrast::Agent::Telemetry::TelemetryException::StackFrame, 'stack_frame')
|
|
48
49
|
@stack_frames << stack_frame
|
|
49
50
|
end
|
|
50
51
|
|
|
52
|
+
# @raise[ArgumentError]
|
|
51
53
|
def module_name= module_name
|
|
52
54
|
@module_name = module_name
|
|
53
55
|
validate_field(VALIDATIONS[:module_name], 'module_name')
|
|
54
56
|
end
|
|
55
57
|
|
|
58
|
+
# @raise[ArgumentError]
|
|
56
59
|
def value= value
|
|
57
60
|
@value = value
|
|
58
61
|
validate_field(VALIDATIONS[:value], 'value')
|
|
@@ -28,6 +28,7 @@ module Contrast
|
|
|
28
28
|
# @return [String]
|
|
29
29
|
attr_reader :module_name
|
|
30
30
|
|
|
31
|
+
# @raise [ArgumentError]
|
|
31
32
|
def initialize function, type
|
|
32
33
|
super()
|
|
33
34
|
@function = function
|
|
@@ -36,11 +37,13 @@ module Contrast
|
|
|
36
37
|
validate(VALIDATIONS)
|
|
37
38
|
end
|
|
38
39
|
|
|
40
|
+
# @raise [ArgumentError]
|
|
39
41
|
def module_name= module_name
|
|
40
42
|
@module_name = module_name
|
|
41
43
|
validate_field(VALIDATIONS[:module_name], 'module_name')
|
|
42
44
|
end
|
|
43
45
|
|
|
46
|
+
# @raise [ArgumentError]
|
|
44
47
|
def to_controlled_hash
|
|
45
48
|
super
|
|
46
49
|
{ function: function, type: type, module: module_name, inContrast: in_contrast }.compact
|
|
@@ -17,4 +17,3 @@ require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_fr
|
|
|
17
17
|
require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception'
|
|
18
18
|
require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_message'
|
|
19
19
|
require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_event'
|
|
20
|
-
require 'contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report'
|