contrast-agent 6.8.0 → 6.9.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/lib/contrast/agent/assess/policy/trigger_method.rb +1 -1
- data/lib/contrast/agent/assess/property/evented.rb +11 -11
- data/lib/contrast/agent/assess.rb +0 -1
- data/lib/contrast/agent/excluder.rb +1 -1
- data/lib/contrast/agent/middleware.rb +8 -2
- data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +116 -0
- data/lib/contrast/agent/protect/rule/base.rb +2 -2
- data/lib/contrast/agent/protect/rule/bot_blocker.rb +1 -1
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +8 -7
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_chained_command.rb +0 -5
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_dangerous_path.rb +0 -5
- data/lib/contrast/agent/protect/rule/path_traversal.rb +4 -3
- data/lib/contrast/agent/protect/rule/sqli.rb +4 -3
- data/lib/contrast/agent/protect/rule/xss.rb +1 -0
- data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +1 -1
- data/lib/contrast/agent/reporting/report.rb +1 -0
- data/lib/contrast/agent/reporting/reporter.rb +34 -0
- data/lib/contrast/agent/reporting/reporter_heartbeat.rb +3 -9
- data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +12 -7
- data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +6 -1
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +2 -2
- data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +239 -93
- data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +10 -23
- data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +10 -9
- data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +12 -0
- data/lib/contrast/agent/reporting/reporting_events/server_reporting_event.rb +8 -0
- data/lib/contrast/agent/reporting/reporting_events/server_settings.rb +40 -0
- data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +6 -0
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +43 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +8 -4
- data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +58 -4
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +4 -3
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +76 -16
- data/lib/contrast/agent/reporting/server_settings_worker.rb +44 -0
- data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +14 -2
- data/lib/contrast/agent/reporting/settings/helpers.rb +7 -0
- data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +39 -2
- data/lib/contrast/agent/reporting/settings/rule_definition.rb +3 -0
- data/lib/contrast/agent/reporting/settings/security_logger.rb +77 -0
- data/lib/contrast/agent/reporting/settings/server_features.rb +9 -0
- data/lib/contrast/agent/reporting/settings/syslog.rb +34 -5
- data/lib/contrast/agent/request.rb +1 -0
- data/lib/contrast/agent/request_handler.rb +5 -10
- data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +1 -1
- data/lib/contrast/agent/thread_watcher.rb +35 -1
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/agent.rb +6 -0
- data/lib/contrast/api/communication/connection_status.rb +15 -0
- data/lib/contrast/components/agent.rb +34 -0
- data/lib/contrast/components/api.rb +23 -0
- data/lib/contrast/components/app_context.rb +23 -3
- data/lib/contrast/components/assess.rb +34 -4
- data/lib/contrast/components/assess_rules.rb +18 -0
- data/lib/contrast/components/base.rb +40 -0
- data/lib/contrast/components/config/sources.rb +95 -0
- data/lib/contrast/components/config.rb +18 -1
- data/lib/contrast/components/heap_dump.rb +10 -0
- data/lib/contrast/components/inventory.rb +15 -2
- data/lib/contrast/components/logger.rb +18 -0
- data/lib/contrast/components/polling.rb +36 -0
- data/lib/contrast/components/protect.rb +48 -1
- data/lib/contrast/components/ruby_component.rb +15 -0
- data/lib/contrast/components/sampling.rb +70 -13
- data/lib/contrast/components/security_logger.rb +13 -0
- data/lib/contrast/components/settings.rb +74 -7
- data/lib/contrast/config/certification_configuration.rb +14 -0
- data/lib/contrast/config/config.rb +46 -0
- data/lib/contrast/config/diagnostics.rb +114 -0
- data/lib/contrast/config/diagnostics_tools.rb +98 -0
- data/lib/contrast/config/effective_config.rb +65 -0
- data/lib/contrast/config/effective_config_value.rb +32 -0
- data/lib/contrast/config/exception_configuration.rb +12 -0
- data/lib/contrast/config/protect_rule_configuration.rb +1 -1
- data/lib/contrast/config/protect_rules_configuration.rb +8 -7
- data/lib/contrast/config/request_audit_configuration.rb +13 -0
- data/lib/contrast/config/server_configuration.rb +41 -2
- data/lib/contrast/configuration.rb +28 -2
- data/lib/contrast/extension/assess/erb.rb +1 -1
- data/lib/contrast/utils/assess/event_limit_utils.rb +31 -9
- data/lib/contrast/utils/assess/trigger_method_utils.rb +5 -4
- data/lib/contrast/utils/hash_digest.rb +2 -2
- data/lib/contrast/utils/input_classification_base.rb +1 -2
- data/lib/contrast/utils/reporting/application_activity_batch_utils.rb +81 -0
- data/lib/contrast/utils/routes_sent.rb +60 -0
- data/lib/contrast/utils/telemetry_client.rb +1 -2
- data/lib/contrast/utils/timer.rb +16 -0
- data/lib/contrast.rb +3 -1
- data/ruby-agent.gemspec +5 -1
- metadata +29 -20
- data/lib/contrast/agent/assess/contrast_event.rb +0 -157
- data/lib/contrast/agent/assess/events/event_factory.rb +0 -34
- data/lib/contrast/agent/assess/events/source_event.rb +0 -46
- data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +0 -36
|
@@ -1,12 +1,18 @@
|
|
|
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/config/base_configuration'
|
|
5
|
+
|
|
4
6
|
module Contrast
|
|
5
7
|
module Config
|
|
6
8
|
# Common Configuration settings. Those in this section pertain to the server identification functionality of the
|
|
7
9
|
# Agent.
|
|
8
10
|
class ServerConfiguration
|
|
9
11
|
include Contrast::Config::BaseConfiguration
|
|
12
|
+
include Contrast::Components::ComponentBase
|
|
13
|
+
|
|
14
|
+
CANON_NAME = 'server'
|
|
15
|
+
CONFIG_VALUES = %w[tags environment version].cs__freeze
|
|
10
16
|
|
|
11
17
|
# @return [String, nil]
|
|
12
18
|
attr_reader :name
|
|
@@ -14,14 +20,19 @@ module Contrast
|
|
|
14
20
|
attr_accessor :path
|
|
15
21
|
# @return [String, nil]
|
|
16
22
|
attr_accessor :type
|
|
17
|
-
|
|
18
|
-
attr_accessor :tags
|
|
23
|
+
attr_writer :tags
|
|
19
24
|
# @return [String, nil]
|
|
20
25
|
attr_accessor :environment
|
|
21
26
|
# @return [String, nil]
|
|
22
27
|
attr_accessor :version
|
|
28
|
+
# @return [String]
|
|
29
|
+
attr_reader :canon_name
|
|
30
|
+
# @return [Array]
|
|
31
|
+
attr_reader :config_values
|
|
23
32
|
|
|
24
33
|
def initialize hsh = {}
|
|
34
|
+
@config_values = CONFIG_VALUES
|
|
35
|
+
@canon_name = CANON_NAME
|
|
25
36
|
return unless hsh
|
|
26
37
|
|
|
27
38
|
@path = hsh[:path]
|
|
@@ -31,6 +42,34 @@ module Contrast
|
|
|
31
42
|
@environment = hsh[:environment]
|
|
32
43
|
@version = hsh[:version]
|
|
33
44
|
end
|
|
45
|
+
|
|
46
|
+
# @return [String, nil]
|
|
47
|
+
def tags
|
|
48
|
+
stringify_array(@tags)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Converts current configuration to effective config values class and appends them to
|
|
52
|
+
# EffectiveConfig class.
|
|
53
|
+
#
|
|
54
|
+
# @param effective_config [Contrast::Agent::DiagnosticsConfig::EffectiveConfig]
|
|
55
|
+
def to_effective_config effective_config
|
|
56
|
+
super
|
|
57
|
+
add_single_effective_value(effective_config,
|
|
58
|
+
'type',
|
|
59
|
+
Contrast::APP_CONTEXT.server_type,
|
|
60
|
+
CANON_NAME,
|
|
61
|
+
"#{ CONTRAST }.#{ CANON_NAME }")
|
|
62
|
+
add_single_effective_value(effective_config,
|
|
63
|
+
'name',
|
|
64
|
+
Contrast::APP_CONTEXT.server_name,
|
|
65
|
+
CANON_NAME,
|
|
66
|
+
"#{ CONTRAST }.#{ CANON_NAME }")
|
|
67
|
+
add_single_effective_value(effective_config,
|
|
68
|
+
'path',
|
|
69
|
+
Contrast::APP_CONTEXT.server_path,
|
|
70
|
+
CANON_NAME,
|
|
71
|
+
"#{ CONTRAST }.#{ CANON_NAME }")
|
|
72
|
+
end
|
|
34
73
|
end
|
|
35
74
|
end
|
|
36
75
|
end
|
|
@@ -13,6 +13,7 @@ require 'contrast/components/scope'
|
|
|
13
13
|
require 'contrast/components/inventory'
|
|
14
14
|
require 'contrast/components/protect'
|
|
15
15
|
require 'contrast/components/assess'
|
|
16
|
+
require 'contrast/components/config/sources'
|
|
16
17
|
require 'contrast/config/server_configuration'
|
|
17
18
|
|
|
18
19
|
module Contrast
|
|
@@ -45,6 +46,12 @@ module Contrast
|
|
|
45
46
|
attr_writer :protect
|
|
46
47
|
# @return [Boolean, nil]
|
|
47
48
|
attr_accessor :enable
|
|
49
|
+
# @return [Hash]
|
|
50
|
+
attr_accessor :loaded_config
|
|
51
|
+
# @return [Contrast::Config::Sources]
|
|
52
|
+
attr_accessor :sources
|
|
53
|
+
# @return [String,nil]
|
|
54
|
+
attr_reader :config_file
|
|
48
55
|
|
|
49
56
|
DEFAULT_YAML_PATH = 'contrast_security.yaml'
|
|
50
57
|
MILLISECOND_MARKER = '_ms'
|
|
@@ -53,18 +60,26 @@ module Contrast
|
|
|
53
60
|
KEYS_TO_REDACT = %i[api_key url service_key user_name].cs__freeze
|
|
54
61
|
REDACTED = '**REDACTED**'
|
|
55
62
|
|
|
56
|
-
def initialize cli_options = nil, default_name = DEFAULT_YAML_PATH
|
|
63
|
+
def initialize cli_options = nil, default_name = DEFAULT_YAML_PATH # rubocop:disable Metrics/AbcSize
|
|
57
64
|
@default_name = default_name
|
|
58
65
|
|
|
59
66
|
# Load config_kv from file
|
|
60
67
|
config_kv = deep_symbolize_all_keys(load_config)
|
|
68
|
+
config_sources = assign_source_to(config_kv, Contrast::Components::Config::Sources::YAML)
|
|
61
69
|
|
|
62
70
|
# Overlay CLI options - they take precedence over config file
|
|
63
71
|
cli_options = deep_symbolize_all_keys(cli_options)
|
|
64
|
-
|
|
72
|
+
if cli_options
|
|
73
|
+
config_kv = deep_merge(cli_options, config_kv)
|
|
74
|
+
config_sources = deep_merge(assign_source_to(cli_options, Contrast::Components::Config::Sources::CLI),
|
|
75
|
+
config_sources)
|
|
76
|
+
end
|
|
65
77
|
|
|
66
78
|
# Some in-flight rewrites to maintain backwards compatibility
|
|
67
79
|
config_kv = update_prop_keys(config_kv)
|
|
80
|
+
@loaded_config = config_kv
|
|
81
|
+
|
|
82
|
+
@sources = Contrast::Components::Config::Sources.new(config_sources)
|
|
68
83
|
|
|
69
84
|
@api = Contrast::Components::Api::Interface.new(config_kv[:api])
|
|
70
85
|
@enable = config_kv[:enable]
|
|
@@ -132,6 +147,7 @@ module Contrast
|
|
|
132
147
|
next
|
|
133
148
|
end
|
|
134
149
|
config = yaml_to_hash(path) || {}
|
|
150
|
+
@config_file = path
|
|
135
151
|
break
|
|
136
152
|
end
|
|
137
153
|
|
|
@@ -307,5 +323,15 @@ module Contrast
|
|
|
307
323
|
def redactable? key
|
|
308
324
|
KEYS_TO_REDACT.include?(key.to_sym)
|
|
309
325
|
end
|
|
326
|
+
|
|
327
|
+
def assign_source_to hash, source = Contrast::Components::Config::Sources::YAML
|
|
328
|
+
hash.transform_values do |value|
|
|
329
|
+
if value.is_a?(Hash)
|
|
330
|
+
assign_source_to(value, source)
|
|
331
|
+
else
|
|
332
|
+
source
|
|
333
|
+
end
|
|
334
|
+
end
|
|
335
|
+
end
|
|
310
336
|
end
|
|
311
337
|
end
|
|
@@ -39,7 +39,7 @@ module ERBPropagator
|
|
|
39
39
|
# @param used_binding [Binding] the binding in of the current event, saved as preshift argument
|
|
40
40
|
# @param erb_pre_result [String] the source saved in the preshift
|
|
41
41
|
# @param properties [Contrast::Agent::Assess::Properties] properties of the target if none create new
|
|
42
|
-
# @param parent_events [Array<Contrast::Agent::
|
|
42
|
+
# @param parent_events [Array<Contrast::Agent::Reporting::FindingEvent>] parents event extracted from the source
|
|
43
43
|
# properties
|
|
44
44
|
# @param ret [String] the Return of the invoked method
|
|
45
45
|
# @return [Array<Symbol>]
|
|
@@ -12,18 +12,19 @@ module Contrast
|
|
|
12
12
|
module EventLimitUtils
|
|
13
13
|
include Contrast::Components::Logger::InstanceMethods
|
|
14
14
|
# Checks to see if the event limit for the policy type has been met or exceeded
|
|
15
|
-
# @param
|
|
16
|
-
|
|
15
|
+
# @param policy [Contrast::Agent::Patching::Policy::MethodPolicy,
|
|
16
|
+
# Contrast::Agent::Patching::Policy::TriggerNode] method to check for event limit
|
|
17
|
+
def event_limit? policy
|
|
17
18
|
return false unless (context = Contrast::Agent::REQUEST_TRACKER.current)
|
|
18
19
|
|
|
19
|
-
if
|
|
20
|
+
if policy.source_node
|
|
20
21
|
max = ::Contrast::ASSESS.max_context_source_events
|
|
21
|
-
return at_limit?(
|
|
22
|
-
|
|
22
|
+
return at_limit?(policy, context.source_event_count, max, context)
|
|
23
23
|
end
|
|
24
|
-
|
|
24
|
+
|
|
25
|
+
if policy.propagation_node
|
|
25
26
|
max = ::Contrast::ASSESS.max_propagation_events
|
|
26
|
-
return at_limit?(
|
|
27
|
+
return at_limit?(policy, context.propagation_event_count, max, context)
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
false # policy does not have limit
|
|
@@ -65,8 +66,10 @@ module Contrast
|
|
|
65
66
|
private
|
|
66
67
|
|
|
67
68
|
# helper method to check limit and log when necessary
|
|
68
|
-
def at_limit? method_policy, current_count, event_max
|
|
69
|
+
def at_limit? method_policy, current_count, event_max, context
|
|
69
70
|
if current_count == event_max
|
|
71
|
+
return if event_limit_counts.key?(get_event_limit_key(method_policy, context))
|
|
72
|
+
|
|
70
73
|
logger.warn('Event Limit Reached:',
|
|
71
74
|
{
|
|
72
75
|
count: current_count,
|
|
@@ -76,16 +79,21 @@ module Contrast
|
|
|
76
79
|
})
|
|
77
80
|
# increment to be over count for logging purposes
|
|
78
81
|
increment_event_count(method_policy)
|
|
82
|
+
increment_event_limit_logs(method_policy, context)
|
|
83
|
+
|
|
79
84
|
return true
|
|
80
85
|
elsif current_count > event_max
|
|
81
|
-
# increment to be over count for logging purposes
|
|
82
86
|
increment_event_count(method_policy)
|
|
87
|
+
return if event_limit_counts.key?(get_event_limit_key(method_policy, context))
|
|
88
|
+
|
|
89
|
+
# increment to be over count for logging purposes
|
|
83
90
|
logger.warn('Event Limit Exceeded:',
|
|
84
91
|
{
|
|
85
92
|
count: current_count,
|
|
86
93
|
policy: method_policy.method_name,
|
|
87
94
|
node: method_policy
|
|
88
95
|
})
|
|
96
|
+
increment_event_limit_logs(method_policy, context)
|
|
89
97
|
return true
|
|
90
98
|
end
|
|
91
99
|
false
|
|
@@ -95,6 +103,20 @@ module Contrast
|
|
|
95
103
|
@_rule_counts ||= Hash.new { |h, k| h[k] = 0 }
|
|
96
104
|
end
|
|
97
105
|
|
|
106
|
+
def event_limit_counts
|
|
107
|
+
@_event_limit_counts ||= Hash.new { |h, k| h[k] = 0 }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def get_event_limit_key method_policy, context
|
|
111
|
+
"#{ method_policy.method_name }_#{ context.request.__id__ }"
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def increment_event_limit_logs method_policy, context
|
|
115
|
+
event_limit_counter = get_event_limit_key(method_policy, context)
|
|
116
|
+
|
|
117
|
+
event_limit_counts[event_limit_counter] += 1
|
|
118
|
+
end
|
|
119
|
+
|
|
98
120
|
# the time threshold for which to track rule counts resets when now >= threshold_time_limit
|
|
99
121
|
# @return [Integer]
|
|
100
122
|
def threshold_time_limit
|
|
@@ -1,12 +1,15 @@
|
|
|
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/utils/assess/event_limit_utils'
|
|
5
|
+
|
|
4
6
|
module Contrast
|
|
5
7
|
module Utils
|
|
6
8
|
module Assess
|
|
7
9
|
# This module will include all methods for some internal validations/appliers in the TriggerMethod module
|
|
8
10
|
# and some other module methods from the same place, so we can ease the main module
|
|
9
11
|
module TriggerMethodUtils
|
|
12
|
+
extend Contrast::Utils::Assess::EventLimitUtils
|
|
10
13
|
# A request is reportable if it is not from ActionController::Live
|
|
11
14
|
#
|
|
12
15
|
# @param env [Hash] the env of the Request
|
|
@@ -33,10 +36,10 @@ module Contrast
|
|
|
33
36
|
|
|
34
37
|
# Finds the first request along the left most tree of parent events
|
|
35
38
|
#
|
|
36
|
-
# @param event [Contrast::Agent::
|
|
39
|
+
# @param event [Contrast::Agent::Reporting::FindingEvent]
|
|
37
40
|
# @return [Contrast::Agent::Request, nil]
|
|
38
41
|
def find_event_request event
|
|
39
|
-
return event.request if event
|
|
42
|
+
return event.request if event&.source_type
|
|
40
43
|
|
|
41
44
|
idx = 0
|
|
42
45
|
while idx <= event.parent_events.length
|
|
@@ -44,9 +47,7 @@ module Contrast
|
|
|
44
47
|
return found if found
|
|
45
48
|
|
|
46
49
|
idx += 1
|
|
47
|
-
return event.request if event.request
|
|
48
50
|
end
|
|
49
|
-
return unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
|
|
50
51
|
|
|
51
52
|
event.request
|
|
52
53
|
end
|
|
@@ -61,8 +61,8 @@ module Contrast
|
|
|
61
61
|
def update_on_sources events
|
|
62
62
|
events.each do |event|
|
|
63
63
|
event.event_sources.each do |source|
|
|
64
|
-
update(source.
|
|
65
|
-
update(source.
|
|
64
|
+
update(source.source_type)
|
|
65
|
+
update(source.source_name)
|
|
66
66
|
end
|
|
67
67
|
end
|
|
68
68
|
end
|
|
@@ -133,8 +133,7 @@ module Contrast
|
|
|
133
133
|
input_eval = Contrast::AGENT_LIB.eval_input(value,
|
|
134
134
|
convert_input_type(input_type),
|
|
135
135
|
Contrast::AGENT_LIB.rule_set[rule_id],
|
|
136
|
-
Contrast::AGENT_LIB.
|
|
137
|
-
eval_option[:WORTHWATCHING])
|
|
136
|
+
Contrast::AGENT_LIB.eval_option[:WORTHWATCHING])
|
|
138
137
|
|
|
139
138
|
ia_result = new_ia_result(rule_id, input_type, request.path, value)
|
|
140
139
|
score = input_eval&.score || 0
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require 'contrast/agent/reporting/reporting_events/application_activity'
|
|
5
|
+
|
|
6
|
+
module Contrast
|
|
7
|
+
module Utils
|
|
8
|
+
module Reporting
|
|
9
|
+
# ApplicationActivityBatchUtils handles batching and reporting of ApplicationActivity events to TeamServer at a
|
|
10
|
+
# set interval
|
|
11
|
+
module ApplicationActivityBatchUtils
|
|
12
|
+
DEFAULT_REPORTING_INTERVAL_MS = 30_000.cs__freeze
|
|
13
|
+
|
|
14
|
+
# @return [Integer] time when activity batch was created in ms
|
|
15
|
+
attr_reader :batch_age
|
|
16
|
+
|
|
17
|
+
# Merge a ApplicationActivity into the ApplicationActivityBatch
|
|
18
|
+
# @param activity [Contrast::Agent::Reporting::ApplicationActivity] from a RequestContext
|
|
19
|
+
def add_activity_to_batch activity
|
|
20
|
+
return unless activity
|
|
21
|
+
|
|
22
|
+
activity_batch.query_count += activity.query_count
|
|
23
|
+
activity_batch.routes << activity.routes
|
|
24
|
+
activity_batch.routes.flatten!
|
|
25
|
+
merge_attackers(activity)
|
|
26
|
+
activity_batch.attach_inventory(activity.inventory) unless activity.inventory.empty?
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# If the batch can be reported, mask the data and add it to the reporting queue, then reset the activity_batch
|
|
30
|
+
def report_batch
|
|
31
|
+
return unless report_batch?
|
|
32
|
+
return unless (reporter = Contrast::Agent.reporter)
|
|
33
|
+
|
|
34
|
+
Contrast::Agent::Reporting::Masker.mask(activity_batch)
|
|
35
|
+
reporter&.send_event(activity_batch)
|
|
36
|
+
reset_activity_batch
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# @return Contrast::Agent::Reporting::ApplicationActivity
|
|
40
|
+
def activity_batch
|
|
41
|
+
return @activity_batch unless @activity_batch.nil?
|
|
42
|
+
|
|
43
|
+
reset_activity_batch
|
|
44
|
+
@activity_batch
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def merge_attackers activity
|
|
50
|
+
return if activity.defend.attackers.empty?
|
|
51
|
+
|
|
52
|
+
activity.defend.attackers.each do |attacker|
|
|
53
|
+
if (existing = activity_batch.defend.find_existing_attacker_activity(attacker))
|
|
54
|
+
attacker.protection_rules.each_key do |key|
|
|
55
|
+
activity_batch.defend.attach_existing(existing, attacker, key)
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
activity_batch.defend.attackers << attacker
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# resets the activity_batch object and it's batch_age
|
|
64
|
+
def reset_activity_batch
|
|
65
|
+
@batch_age = Contrast::Utils::Timer.now_ms
|
|
66
|
+
@activity_batch = Contrast::Agent::Reporting::ApplicationActivity.new
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @return [Boolean] if the age of the batch is outside the reporting interval
|
|
70
|
+
def report_batch?
|
|
71
|
+
reporting_interval <= (Contrast::Utils::Timer.now_ms - batch_age)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# @return [Integer] interval to report to TeamServer in seconds
|
|
75
|
+
def reporting_interval
|
|
76
|
+
Contrast::AGENT.polling.batch_reporting_interval_ms.to_i || DEFAULT_REPORTING_INTERVAL_MS
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# require 'contrast/components/logger'
|
|
5
|
+
# require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_event'
|
|
6
|
+
|
|
7
|
+
module Contrast
|
|
8
|
+
module Utils
|
|
9
|
+
# This is the RoutesSent class, which determines whether observed routes can be sent to TeamServer.
|
|
10
|
+
# Routes that have not been seen (according to the cache) can be sent, as well as any route that
|
|
11
|
+
# # has been seen but not within the time limit.
|
|
12
|
+
class RoutesSent
|
|
13
|
+
# include Contrast::Components::Logger::InstanceMethods
|
|
14
|
+
ROUTES_LIMIT = 500
|
|
15
|
+
TIME_LIMIT_IN_SECONDS = 3600
|
|
16
|
+
|
|
17
|
+
attr_accessor :cache
|
|
18
|
+
|
|
19
|
+
def initialize
|
|
20
|
+
@cache = {}
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Determine whether the provided route can be sent to TeamServer.
|
|
24
|
+
#
|
|
25
|
+
# @param [Contrast::Agent::Reporting::ObservedRoute] the route
|
|
26
|
+
# @return [boolean]
|
|
27
|
+
def sendable? route
|
|
28
|
+
route_hash = route.hash_id
|
|
29
|
+
|
|
30
|
+
# If hash doesn't exist in @cache...
|
|
31
|
+
# - Add hash to @cache (with Time.now)
|
|
32
|
+
# - Clear oldest entries (if more than ROUTES_LIMIT)
|
|
33
|
+
# - Return *true*
|
|
34
|
+
unless cache.key?(route_hash)
|
|
35
|
+
cache[route_hash] = Time.now
|
|
36
|
+
remove_oldest_entries!
|
|
37
|
+
return true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# If hash exists in @cache...
|
|
41
|
+
# - Return *true* if more than a minute since time recorded for hash
|
|
42
|
+
# - Return *false* if not than a minute since time recorded for hash
|
|
43
|
+
return false unless Time.now.to_i - cache.fetch(route_hash, 0).to_i > TIME_LIMIT_IN_SECONDS
|
|
44
|
+
|
|
45
|
+
cache[route_hash] = Time.now
|
|
46
|
+
true
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
private
|
|
50
|
+
|
|
51
|
+
def remove_oldest_entries!
|
|
52
|
+
return if cache.size < ROUTES_LIMIT
|
|
53
|
+
|
|
54
|
+
route_hashes = cache.sort_by { |_, v| -v.tv_nsec }.
|
|
55
|
+
to_h.keys.slice(0, ROUTES_LIMIT)
|
|
56
|
+
@cache = cache.slice(*route_hashes)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -97,8 +97,7 @@ module Contrast
|
|
|
97
97
|
# @param event [Contrast::Agent::Telemetry::Event, Array<Contrast::Agent::Telemetry::TelemetryException::Event>]
|
|
98
98
|
# @return [String] - JSON
|
|
99
99
|
def get_event_json event
|
|
100
|
-
|
|
101
|
-
hsh.to_json
|
|
100
|
+
Array(event.to_controlled_hash).to_json
|
|
102
101
|
rescue Exception => e # rubocop:disable Lint/RescueException
|
|
103
102
|
logger.error('Unable to convert TelemetryEvent to JSON string', e, hsh)
|
|
104
103
|
raise(e)
|
data/lib/contrast/utils/timer.rb
CHANGED
|
@@ -22,6 +22,22 @@ module Contrast
|
|
|
22
22
|
def self.now_ms
|
|
23
23
|
(Time.now.to_f * 1000).to_i
|
|
24
24
|
end
|
|
25
|
+
|
|
26
|
+
# Return current time in iso8601 format.
|
|
27
|
+
#
|
|
28
|
+
# @return[String]
|
|
29
|
+
def self.time_now
|
|
30
|
+
Time.now.utc.iso8601(7)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Converts time given in ms format form TS to HttpDate.
|
|
34
|
+
# Returns time format for If-Modified-Since: <day-name>, <day> <month> <year> <hour>:<minute>:<second> GMT
|
|
35
|
+
# Note: The Time class treats GMT (Greenwich Mean Time) and UTC (Coordinated Universal Time) as equivalent.
|
|
36
|
+
#
|
|
37
|
+
# @param time [Integer] time in ms.
|
|
38
|
+
def self.ms_to_httpdate time
|
|
39
|
+
Time.at(time / 1000).httpdate unless time.nil?
|
|
40
|
+
end
|
|
25
41
|
end
|
|
26
42
|
end
|
|
27
43
|
end
|
data/lib/contrast.rb
CHANGED
|
@@ -60,12 +60,13 @@ require 'contrast/components/protect'
|
|
|
60
60
|
require 'contrast/components/sampling'
|
|
61
61
|
require 'contrast/components/scope'
|
|
62
62
|
require 'contrast/components/settings'
|
|
63
|
+
require 'contrast/utils/routes_sent'
|
|
63
64
|
require 'contrast/utils/telemetry_hash'
|
|
64
65
|
require 'contrast/utils/telemetry'
|
|
65
66
|
require 'contrast/agent/telemetry/events/exceptions/telemetry_exception_event'
|
|
66
67
|
require 'contrast/agent_lib/interface'
|
|
67
68
|
|
|
68
|
-
module Contrast
|
|
69
|
+
module Contrast # :nodoc:
|
|
69
70
|
CONFIG = Contrast::Components::Config::Interface.new
|
|
70
71
|
SCOPE = Contrast::Components::Scope::Interface.new
|
|
71
72
|
API = CONFIG.api
|
|
@@ -81,6 +82,7 @@ end
|
|
|
81
82
|
|
|
82
83
|
module Contrast
|
|
83
84
|
TELEMETRY_EXCEPTIONS = (Contrast::Utils::TelemetryHash.new if Contrast::Utils::Telemetry.exceptions_enabled?)
|
|
85
|
+
ROUTES_SENT = Contrast::Utils::RoutesSent.new
|
|
84
86
|
end
|
|
85
87
|
|
|
86
88
|
# This needs to be required very early, after component interfaces, and before instrumentation attempts
|
data/ruby-agent.gemspec
CHANGED
|
@@ -101,7 +101,11 @@ end
|
|
|
101
101
|
|
|
102
102
|
# Dependencies not mocked out during RSpec that we test real code of, beyond just frameworks.
|
|
103
103
|
def self.add_tested_gems spec
|
|
104
|
-
|
|
104
|
+
if RUBY_VERSION < '3.0.0'
|
|
105
|
+
spec.add_development_dependency 'async', '~> 1.30.3'
|
|
106
|
+
else
|
|
107
|
+
spec.add_development_dependency 'async'
|
|
108
|
+
end
|
|
105
109
|
spec.add_development_dependency 'execjs'
|
|
106
110
|
spec.add_development_dependency 'rhino'
|
|
107
111
|
spec.add_development_dependency 'sqlite3'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: contrast-agent
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 6.
|
|
4
|
+
version: 6.9.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- galen.palmer@contrastsecurity.com
|
|
@@ -13,7 +13,7 @@ authors:
|
|
|
13
13
|
autorequire:
|
|
14
14
|
bindir: exe
|
|
15
15
|
cert_chain: []
|
|
16
|
-
date: 2022-
|
|
16
|
+
date: 2022-10-07 00:00:00.000000000 Z
|
|
17
17
|
dependencies:
|
|
18
18
|
- !ruby/object:Gem::Dependency
|
|
19
19
|
name: bundler
|
|
@@ -305,16 +305,16 @@ dependencies:
|
|
|
305
305
|
name: async
|
|
306
306
|
requirement: !ruby/object:Gem::Requirement
|
|
307
307
|
requirements:
|
|
308
|
-
- - "
|
|
308
|
+
- - "~>"
|
|
309
309
|
- !ruby/object:Gem::Version
|
|
310
|
-
version:
|
|
310
|
+
version: 1.30.3
|
|
311
311
|
type: :development
|
|
312
312
|
prerelease: false
|
|
313
313
|
version_requirements: !ruby/object:Gem::Requirement
|
|
314
314
|
requirements:
|
|
315
|
-
- - "
|
|
315
|
+
- - "~>"
|
|
316
316
|
- !ruby/object:Gem::Version
|
|
317
|
-
version:
|
|
317
|
+
version: 1.30.3
|
|
318
318
|
- !ruby/object:Gem::Dependency
|
|
319
319
|
name: execjs
|
|
320
320
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -678,22 +678,22 @@ email:
|
|
|
678
678
|
executables: []
|
|
679
679
|
extensions:
|
|
680
680
|
- ext/cs__common/extconf.rb
|
|
681
|
-
- ext/
|
|
682
|
-
- ext/
|
|
683
|
-
- ext/
|
|
681
|
+
- ext/cs__assess_module/extconf.rb
|
|
682
|
+
- ext/cs__assess_marshal_module/extconf.rb
|
|
683
|
+
- ext/cs__assess_array/extconf.rb
|
|
684
|
+
- ext/cs__os_information/extconf.rb
|
|
685
|
+
- ext/cs__assess_string_interpolation/extconf.rb
|
|
684
686
|
- ext/cs__assess_regexp/extconf.rb
|
|
687
|
+
- ext/cs__assess_string/extconf.rb
|
|
688
|
+
- ext/cs__assess_hash/extconf.rb
|
|
685
689
|
- ext/cs__assess_yield_track/extconf.rb
|
|
686
|
-
- ext/cs__assess_string_interpolation/extconf.rb
|
|
687
|
-
- ext/cs__scope/extconf.rb
|
|
688
690
|
- ext/cs__contrast_patch/extconf.rb
|
|
689
|
-
- ext/cs__assess_module/extconf.rb
|
|
690
691
|
- ext/cs__assess_kernel/extconf.rb
|
|
691
|
-
- ext/cs__assess_marshal_module/extconf.rb
|
|
692
692
|
- ext/cs__assess_test/extconf.rb
|
|
693
|
-
- ext/
|
|
694
|
-
- ext/cs__assess_array/extconf.rb
|
|
695
|
-
- ext/cs__tests/extconf.rb
|
|
693
|
+
- ext/cs__scope/extconf.rb
|
|
696
694
|
- ext/cs__assess_fiber_track/extconf.rb
|
|
695
|
+
- ext/cs__tests/extconf.rb
|
|
696
|
+
- ext/cs__assess_basic_object/extconf.rb
|
|
697
697
|
extra_rdoc_files: []
|
|
698
698
|
files:
|
|
699
699
|
- ".clang-format"
|
|
@@ -895,11 +895,8 @@ files:
|
|
|
895
895
|
- lib/contrast.rb
|
|
896
896
|
- lib/contrast/agent.rb
|
|
897
897
|
- lib/contrast/agent/assess.rb
|
|
898
|
-
- lib/contrast/agent/assess/contrast_event.rb
|
|
899
898
|
- lib/contrast/agent/assess/contrast_object.rb
|
|
900
899
|
- lib/contrast/agent/assess/events/event_data.rb
|
|
901
|
-
- lib/contrast/agent/assess/events/event_factory.rb
|
|
902
|
-
- lib/contrast/agent/assess/events/source_event.rb
|
|
903
900
|
- lib/contrast/agent/assess/finalizers/freeze.rb
|
|
904
901
|
- lib/contrast/agent/assess/finalizers/hash.rb
|
|
905
902
|
- lib/contrast/agent/assess/policy/dynamic_source_factory.rb
|
|
@@ -997,6 +994,7 @@ files:
|
|
|
997
994
|
- lib/contrast/agent/patching/policy/trigger_node.rb
|
|
998
995
|
- lib/contrast/agent/protect/exploitable_collection.rb
|
|
999
996
|
- lib/contrast/agent/protect/input_analyzer/input_analyzer.rb
|
|
997
|
+
- lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb
|
|
1000
998
|
- lib/contrast/agent/protect/policy/applies_command_injection_rule.rb
|
|
1001
999
|
- lib/contrast/agent/protect/policy/applies_deserialization_rule.rb
|
|
1002
1000
|
- lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb
|
|
@@ -1113,8 +1111,8 @@ files:
|
|
|
1113
1111
|
- lib/contrast/agent/reporting/reporting_events/route_coverage.rb
|
|
1114
1112
|
- lib/contrast/agent/reporting/reporting_events/route_discovery.rb
|
|
1115
1113
|
- lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb
|
|
1116
|
-
- lib/contrast/agent/reporting/reporting_events/server_activity.rb
|
|
1117
1114
|
- lib/contrast/agent/reporting/reporting_events/server_reporting_event.rb
|
|
1115
|
+
- lib/contrast/agent/reporting/reporting_events/server_settings.rb
|
|
1118
1116
|
- lib/contrast/agent/reporting/reporting_utilities/audit.rb
|
|
1119
1117
|
- lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb
|
|
1120
1118
|
- lib/contrast/agent/reporting/reporting_utilities/endpoints.rb
|
|
@@ -1127,6 +1125,7 @@ files:
|
|
|
1127
1125
|
- lib/contrast/agent/reporting/reporting_utilities/response_handler.rb
|
|
1128
1126
|
- lib/contrast/agent/reporting/reporting_utilities/response_handler_mode.rb
|
|
1129
1127
|
- lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb
|
|
1128
|
+
- lib/contrast/agent/reporting/server_settings_worker.rb
|
|
1130
1129
|
- lib/contrast/agent/reporting/settings/application_settings.rb
|
|
1131
1130
|
- lib/contrast/agent/reporting/settings/assess.rb
|
|
1132
1131
|
- lib/contrast/agent/reporting/settings/assess_server_feature.rb
|
|
@@ -1145,6 +1144,7 @@ files:
|
|
|
1145
1144
|
- lib/contrast/agent/reporting/settings/rule_definition.rb
|
|
1146
1145
|
- lib/contrast/agent/reporting/settings/sampling.rb
|
|
1147
1146
|
- lib/contrast/agent/reporting/settings/sanitizer.rb
|
|
1147
|
+
- lib/contrast/agent/reporting/settings/security_logger.rb
|
|
1148
1148
|
- lib/contrast/agent/reporting/settings/sensitive_data_masking.rb
|
|
1149
1149
|
- lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb
|
|
1150
1150
|
- lib/contrast/agent/reporting/settings/server_features.rb
|
|
@@ -1195,9 +1195,11 @@ files:
|
|
|
1195
1195
|
- lib/contrast/components/assess_rules.rb
|
|
1196
1196
|
- lib/contrast/components/base.rb
|
|
1197
1197
|
- lib/contrast/components/config.rb
|
|
1198
|
+
- lib/contrast/components/config/sources.rb
|
|
1198
1199
|
- lib/contrast/components/heap_dump.rb
|
|
1199
1200
|
- lib/contrast/components/inventory.rb
|
|
1200
1201
|
- lib/contrast/components/logger.rb
|
|
1202
|
+
- lib/contrast/components/polling.rb
|
|
1201
1203
|
- lib/contrast/components/protect.rb
|
|
1202
1204
|
- lib/contrast/components/ruby_component.rb
|
|
1203
1205
|
- lib/contrast/components/sampling.rb
|
|
@@ -1208,6 +1210,11 @@ files:
|
|
|
1208
1210
|
- lib/contrast/config/api_proxy_configuration.rb
|
|
1209
1211
|
- lib/contrast/config/base_configuration.rb
|
|
1210
1212
|
- lib/contrast/config/certification_configuration.rb
|
|
1213
|
+
- lib/contrast/config/config.rb
|
|
1214
|
+
- lib/contrast/config/diagnostics.rb
|
|
1215
|
+
- lib/contrast/config/diagnostics_tools.rb
|
|
1216
|
+
- lib/contrast/config/effective_config.rb
|
|
1217
|
+
- lib/contrast/config/effective_config_value.rb
|
|
1211
1218
|
- lib/contrast/config/env_variables.rb
|
|
1212
1219
|
- lib/contrast/config/exception_configuration.rb
|
|
1213
1220
|
- lib/contrast/config/protect_rule_configuration.rb
|
|
@@ -1288,9 +1295,11 @@ files:
|
|
|
1288
1295
|
- lib/contrast/utils/os.rb
|
|
1289
1296
|
- lib/contrast/utils/patching/policy/patch_utils.rb
|
|
1290
1297
|
- lib/contrast/utils/patching/policy/patcher_utils.rb
|
|
1298
|
+
- lib/contrast/utils/reporting/application_activity_batch_utils.rb
|
|
1291
1299
|
- lib/contrast/utils/request_utils.rb
|
|
1292
1300
|
- lib/contrast/utils/resource_loader.rb
|
|
1293
1301
|
- lib/contrast/utils/response_utils.rb
|
|
1302
|
+
- lib/contrast/utils/routes_sent.rb
|
|
1294
1303
|
- lib/contrast/utils/sha256_builder.rb
|
|
1295
1304
|
- lib/contrast/utils/stack_trace_utils.rb
|
|
1296
1305
|
- lib/contrast/utils/string_utils.rb
|