contrast-agent 6.2.0 → 6.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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'
|