contrast-agent 6.4.0 → 6.6.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__contrast_patch/cs__contrast_patch.c +14 -1
- data/lib/contrast/agent/assess/finalizers/hash.rb +1 -0
- data/lib/contrast/agent/assess/policy/propagation_method.rb +5 -1
- data/lib/contrast/agent/assess/policy/propagator/custom.rb +4 -0
- data/lib/contrast/agent/assess/policy/propagator/database_write.rb +5 -0
- data/lib/contrast/agent/assess/policy/propagator/split.rb +3 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +5 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +8 -2
- data/lib/contrast/agent/assess/tracker.rb +12 -0
- data/lib/contrast/agent/inventory/database_config.rb +2 -1
- data/lib/contrast/agent/inventory/dependency_analysis.rb +2 -2
- data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +1 -1
- data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
- data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
- data/lib/contrast/agent/patching/policy/method_policy.rb +3 -3
- data/lib/contrast/agent/protect/rule/base.rb +1 -1
- data/lib/contrast/agent/reporting/reporter_heartbeat.rb +1 -3
- data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +17 -21
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +26 -3
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +5 -5
- data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -1
- data/lib/contrast/agent/request_context.rb +8 -0
- data/lib/contrast/agent/service_heartbeat.rb +2 -3
- data/lib/contrast/agent/static_analysis.rb +1 -1
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/agent/worker_thread.rb +10 -0
- data/lib/contrast/api/communication/response_processor.rb +1 -1
- data/lib/contrast/components/agent.rb +52 -14
- data/lib/contrast/components/api.rb +60 -23
- data/lib/contrast/components/assess.rb +16 -0
- data/lib/contrast/components/contrast_service.rb +1 -1
- data/lib/contrast/components/heap_dump.rb +51 -1
- data/lib/contrast/components/inventory.rb +19 -13
- data/lib/contrast/components/logger.rb +18 -0
- data/lib/contrast/components/protect.rb +41 -1
- data/lib/contrast/components/sampling.rb +29 -0
- data/lib/contrast/config/assess_configuration.rb +33 -3
- data/lib/contrast/config/base_configuration.rb +8 -2
- data/lib/contrast/config/root_configuration.rb +19 -16
- data/lib/contrast/config/service_configuration.rb +4 -4
- data/lib/contrast/config.rb +0 -9
- data/lib/contrast/extension/object.rb +19 -0
- data/lib/contrast/framework/rails/support.rb +7 -3
- data/lib/contrast/logger/log.rb +2 -1
- data/lib/contrast/utils/assess/event_limit_utils.rb +96 -0
- data/lib/contrast/utils/assess/propagation_method_utils.rb +27 -7
- data/lib/contrast/utils/log_utils.rb +2 -2
- data/lib/contrast/utils/net_http_base.rb +2 -2
- data/lib/contrast/utils/patching/policy/patch_utils.rb +1 -1
- data/lib/contrast.rb +6 -21
- data/resources/assess/policy.json +15 -12
- data/resources/deadzone/policy.json +139 -19
- data/ruby-agent.gemspec +2 -0
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +43 -20
- data/lib/contrast/config/agent_configuration.rb +0 -63
- data/lib/contrast/config/api_configuration.rb +0 -56
- data/lib/contrast/config/heap_dump_configuration.rb +0 -59
- data/lib/contrast/config/inventory_configuration.rb +0 -33
- data/lib/contrast/config/logger_configuration.rb +0 -26
- data/lib/contrast/config/protect_configuration.rb +0 -33
- data/lib/contrast/config/sampling_configuration.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b9901918f58625ea7f9366f73110afcdd5f05e119261ba9a08f24f36903fe897
|
4
|
+
data.tar.gz: c618ebc74b006529e2317cd62ba59fabbba9d0c8fbf24c7988dfd98ec627b04e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d2f584a6658ab0e316b41021575888d9ecc1eaacf79d971492fd2e6317609bfd0cb3a762a64d620b08fc18c76e2434d05cc3d82f8d587c86cdae5116df6cae61
|
7
|
+
data.tar.gz: df8f941fe730188be0bc3b69bd9a9d6d60f9695be8ee8e8eb0b6e35ab1207d97debba28220ff796bec702ad3b158f53f00f87a58f1c14939092ed843bef66715
|
@@ -101,7 +101,18 @@ VALUE rescue_func(VALUE arg1) {
|
|
101
101
|
return Qnil;
|
102
102
|
}
|
103
103
|
|
104
|
+
/**
|
105
|
+
* In the event that the original_method call throws an exception we need to ensure that contrast_post_patch is called
|
106
|
+
* to report that error. However, if there is no error we will call post_patch with the original_return instead of
|
107
|
+
* Qnil.
|
108
|
+
*
|
109
|
+
**/
|
104
110
|
VALUE contrast_patch_call_ensure(const VALUE *args) {
|
111
|
+
// we do not need to ensure that post patch is called if no error was thrown
|
112
|
+
if(!RTEST(rb_errinfo())) {
|
113
|
+
return Qnil;
|
114
|
+
}
|
115
|
+
|
105
116
|
int argc;
|
106
117
|
VALUE object, preshift, method_policy, method;
|
107
118
|
VALUE *argv;
|
@@ -125,6 +136,7 @@ VALUE ensure_wrapper(const VALUE *args) {
|
|
125
136
|
original_args = (VALUE)args[1];
|
126
137
|
ensure_args = (VALUE)args[2];
|
127
138
|
|
139
|
+
//this ensure if being treated as a rescue due to issues surrounding Kernel#throw
|
128
140
|
return rb_ensure(original_method, original_args, contrast_patch_call_ensure,
|
129
141
|
(VALUE)ensure_args);
|
130
142
|
}
|
@@ -220,13 +232,14 @@ VALUE contrast_run_patches(const VALUE *wrapped_args) {
|
|
220
232
|
* If the original method threw an exception, contrast_patch_call_rescue
|
221
233
|
* re-raises the original exception, which unwinds the stack back to the
|
222
234
|
* call site. This means the rest of this function is not executed.
|
235
|
+
* post_patch is called in the ensure_wrapper on exception. rb_rescue
|
236
|
+
* raises the exception so the below will not be executed in that event.
|
223
237
|
*/
|
224
238
|
|
225
239
|
/* Invoke Contrast post-call patching. */
|
226
240
|
contrast_call_post_patch(method_policy, preshift, object,
|
227
241
|
original_ret, argc, argv);
|
228
242
|
|
229
|
-
/* Special case for tracking frozen sources */
|
230
243
|
return original_ret;
|
231
244
|
}
|
232
245
|
|
@@ -8,6 +8,7 @@ require 'contrast/components/logger'
|
|
8
8
|
require 'contrast/utils/object_share'
|
9
9
|
require 'contrast/utils/sha256_builder'
|
10
10
|
require 'contrast/utils/assess/propagation_method_utils'
|
11
|
+
require 'contrast/utils/assess/event_limit_utils'
|
11
12
|
require 'contrast/agent/assess/events/event_data'
|
12
13
|
require 'contrast/utils/assess/object_store'
|
13
14
|
|
@@ -21,6 +22,7 @@ module Contrast
|
|
21
22
|
module PropagationMethod
|
22
23
|
extend Contrast::Components::Logger::InstanceMethods
|
23
24
|
extend Contrast::Utils::Assess::PropagationMethodUtils
|
25
|
+
extend Contrast::Utils::Assess::EventLimitUtils
|
24
26
|
|
25
27
|
@properties = Contrast::Utils::Assess::ObjectStore.new
|
26
28
|
|
@@ -38,6 +40,7 @@ module Contrast
|
|
38
40
|
def apply_propagation method_policy, preshift, object, ret, args, block
|
39
41
|
return unless (propagation_node = method_policy.propagation_node)
|
40
42
|
return unless propagation_node.use_original_object? || preshift
|
43
|
+
return if event_limit?(method_policy)
|
41
44
|
|
42
45
|
target = determine_target(propagation_node, ret, object, args)
|
43
46
|
propagation_data = Contrast::Agent::Assess::Events::EventData.new(nil, nil, object, ret, args)
|
@@ -184,7 +187,7 @@ module Contrast
|
|
184
187
|
# @param _block [Block] the Block passed to the original method
|
185
188
|
def handle_cs_properties_propagation propagation_node, preshift, target, propagation_data, _block
|
186
189
|
return if propagation_node.action == NOOP_ACTION
|
187
|
-
return unless can_propagate?(propagation_node, preshift, target)
|
190
|
+
return unless can_propagate?(propagation_node, preshift, target, propagation_data)
|
188
191
|
return unless (propagation_class = find_propagation_class(propagation_node))
|
189
192
|
|
190
193
|
# If we are using the original object tracking, the preshift object is not created.
|
@@ -192,6 +195,7 @@ module Contrast
|
|
192
195
|
source = propagation_node.use_original_object? ? propagation_data.object : preshift
|
193
196
|
handle_propagation(propagation_class, propagation_node, source, target)
|
194
197
|
update_properties(propagation_node, target, propagation_data)
|
198
|
+
increment_event_count(propagation_node)
|
195
199
|
end
|
196
200
|
|
197
201
|
def handle_propagation propagation_class, propagation_node, source, target
|
@@ -2,6 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'contrast/extension/module'
|
5
|
+
require 'contrast/utils/assess/event_limit_utils'
|
5
6
|
|
6
7
|
module Contrast
|
7
8
|
module Agent
|
@@ -13,6 +14,8 @@ module Contrast
|
|
13
14
|
# action knows the class and method it should call to preform this
|
14
15
|
# action.
|
15
16
|
module Custom
|
17
|
+
extend Contrast::Utils::Assess::EventLimitUtils
|
18
|
+
|
16
19
|
class << self
|
17
20
|
def propagate propagation_node, preshift, ret, block
|
18
21
|
clazz = propagation_node.patch_class
|
@@ -26,6 +29,7 @@ module Contrast
|
|
26
29
|
propagation_node.patch_class = clazz
|
27
30
|
end
|
28
31
|
clazz.send(method, propagation_node, preshift, ret, block)
|
32
|
+
increment_event_count(propagation_node)
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
@@ -1,6 +1,8 @@
|
|
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 Agent
|
6
8
|
module Assess
|
@@ -11,6 +13,8 @@ module Contrast
|
|
11
13
|
# results in new source nodes to track which columns in the database
|
12
14
|
# have been tainted.
|
13
15
|
class DatabaseWrite < Contrast::Agent::Assess::Policy::Propagator::Base
|
16
|
+
extend Contrast::Utils::Assess::EventLimitUtils
|
17
|
+
|
14
18
|
class << self
|
15
19
|
def propagate propagation_node, preshift, target
|
16
20
|
return unless Contrast::ASSESS.require_dynamic_sources?
|
@@ -22,6 +26,7 @@ module Contrast
|
|
22
26
|
known_tainted = ::Contrast::ASSESS.tainted_columns[class_name]
|
23
27
|
propagation_node.sources.each do |source|
|
24
28
|
handle_write(propagation_node, source, preshift, target, known_tainted, tainted_columns)
|
29
|
+
increment_event_count(propagation_node)
|
25
30
|
end
|
26
31
|
return if tainted_columns.empty?
|
27
32
|
|
@@ -6,6 +6,7 @@ require 'contrast/components/agent'
|
|
6
6
|
require 'contrast/components/logger'
|
7
7
|
require 'contrast/components/scope'
|
8
8
|
require 'contrast/utils/thread_tracker'
|
9
|
+
require 'contrast/utils/assess/event_limit_utils'
|
9
10
|
require 'contrast/utils/assess/split_utils'
|
10
11
|
require 'contrast/agent/assess/events/event_data'
|
11
12
|
|
@@ -20,6 +21,7 @@ module Contrast
|
|
20
21
|
extend Contrast::Components::Scope::InstanceMethods
|
21
22
|
extend Contrast::Components::Logger::InstanceMethods
|
22
23
|
extend Contrast::Utils::Assess::SplitUtils
|
24
|
+
extend Contrast::Utils::Assess::EventLimitUtils
|
23
25
|
|
24
26
|
SPLIT_TRACKER = Contrast::Utils::ThreadTracker.new
|
25
27
|
|
@@ -42,6 +44,7 @@ module Contrast
|
|
42
44
|
return unless (source_properties = Contrast::Agent::Assess::Tracker.properties(source))
|
43
45
|
|
44
46
|
update_element_properties(propagation_node, target, preshift, source_properties)
|
47
|
+
increment_event_count(propagation_node)
|
45
48
|
nil
|
46
49
|
end
|
47
50
|
|
@@ -7,6 +7,7 @@ require 'contrast/components/logger'
|
|
7
7
|
require 'contrast/utils/object_share'
|
8
8
|
require 'contrast/utils/sha256_builder'
|
9
9
|
require 'contrast/utils/assess/source_method_utils'
|
10
|
+
require 'contrast/utils/assess/event_limit_utils'
|
10
11
|
require 'contrast/agent/assess/events/event_data'
|
11
12
|
|
12
13
|
module Contrast
|
@@ -19,6 +20,7 @@ module Contrast
|
|
19
20
|
module SourceMethod
|
20
21
|
extend Contrast::Components::Logger::InstanceMethods
|
21
22
|
extend Contrast::Utils::Assess::SourceMethodUtils
|
23
|
+
extend Contrast::Utils::Assess::EventLimitUtils
|
22
24
|
|
23
25
|
PARAMETER_TYPE = 'PARAMETER'
|
24
26
|
PARAMETER_KEY_TYPE = 'PARAMETER_KEY'
|
@@ -37,6 +39,7 @@ module Contrast
|
|
37
39
|
# @param args [Array<Object>] the Arguments with which the method was invoked
|
38
40
|
def apply_source method_policy, object, ret, args
|
39
41
|
return unless analyze?(method_policy, object, ret, args)
|
42
|
+
return if event_limit?(method_policy)
|
40
43
|
return unless (source_node = method_policy.source_node)
|
41
44
|
|
42
45
|
# used to hold the object and ret
|
@@ -66,6 +69,8 @@ module Contrast
|
|
66
69
|
context = Contrast::Agent::REQUEST_TRACKER.current
|
67
70
|
return unless context && source_node && target
|
68
71
|
|
72
|
+
increment_event_count(source_node)
|
73
|
+
|
69
74
|
source_name ||= determine_source_name(source_node, source_data.object, source_data.ret, *args)
|
70
75
|
# We know we only work on certain things.
|
71
76
|
# Skip if this isn't one of them
|
@@ -25,6 +25,7 @@ module Contrast
|
|
25
25
|
module TriggerMethod # rubocop:disable Metrics/ModuleLength
|
26
26
|
extend Contrast::Components::Logger::InstanceMethods
|
27
27
|
extend Contrast::Utils::Assess::TriggerMethodUtils
|
28
|
+
extend Contrast::Utils::Assess::EventLimitUtils
|
28
29
|
|
29
30
|
# The level of TeamServer compliance our traces meet when in the abnormal condition of being dataflow rules
|
30
31
|
# without routes.
|
@@ -48,6 +49,7 @@ module Contrast
|
|
48
49
|
# @param args [Array<Object>] the Arguments with which the method was invoked
|
49
50
|
def apply_trigger_rule trigger_node, object, ret, args
|
50
51
|
return if trigger_node.nil?
|
52
|
+
return if event_limit_for_rule?(trigger_node.rule_id)
|
51
53
|
|
52
54
|
context = Contrast::Agent::REQUEST_TRACKER.current
|
53
55
|
# return if there is no context and the flag is set to default => false
|
@@ -102,6 +104,12 @@ module Contrast
|
|
102
104
|
request = find_request(source)
|
103
105
|
return unless reportable?(request&.env)
|
104
106
|
|
107
|
+
process_reportable_finding(trigger_node, source, object, ret, request, *args)
|
108
|
+
rescue StandardError => e
|
109
|
+
logger.error('Unable to build a finding', e, rule: trigger_node.rule_id, node_id: trigger_node.id)
|
110
|
+
end
|
111
|
+
|
112
|
+
def process_reportable_finding trigger_node, source, object, ret, request, *args
|
105
113
|
if Contrast::Agent::Reporter.enabled?
|
106
114
|
handle_new_finding(trigger_node, source, object, ret, request, *args)
|
107
115
|
else # TODO: RUBY-1438 -- remove
|
@@ -112,8 +120,6 @@ module Contrast
|
|
112
120
|
rule: trigger_node.rule_id)
|
113
121
|
report_finding(finding, request)
|
114
122
|
end
|
115
|
-
rescue StandardError => e
|
116
|
-
logger.error('Unable to build a finding', e, rule: trigger_node.rule_id, node_id: trigger_node.id)
|
117
123
|
end
|
118
124
|
|
119
125
|
# Given a finding, append it to an activity message and send it to the Service for processing. If an
|
@@ -12,6 +12,7 @@ module Contrast
|
|
12
12
|
# have tightly coupled dependencies on each other.
|
13
13
|
class Tracker
|
14
14
|
PROPERTIES_HASH = Contrast::Agent::Assess::Finalizers::Hash.new
|
15
|
+
KEEP_AGE = 600_000.cs__freeze # 10 minutes
|
15
16
|
|
16
17
|
class << self
|
17
18
|
# Retrieve the properties of the given Object, iff they exist.
|
@@ -55,6 +56,17 @@ module Contrast
|
|
55
56
|
def copy source, target
|
56
57
|
PROPERTIES_HASH[target] ||= properties(source).dup
|
57
58
|
end
|
59
|
+
|
60
|
+
# Clean PROPERTIES_HASH of any values older than KEEP_AGE ms or
|
61
|
+
# have nil properties
|
62
|
+
def cleanup!
|
63
|
+
PROPERTIES_HASH.delete_if do |_k, properties|
|
64
|
+
return true if properties.nil?
|
65
|
+
return false unless (event = properties&.event)
|
66
|
+
|
67
|
+
KEEP_AGE <= (Contrast::Utils::Timer.now_ms - event.time)
|
68
|
+
end
|
69
|
+
end
|
58
70
|
end
|
59
71
|
end
|
60
72
|
end
|
@@ -18,8 +18,8 @@ module Contrast
|
|
18
18
|
# @return [Array<Contrast::Agent::Reporting::LibraryDiscovery>] direct report form of
|
19
19
|
# Gem::Specification that have been loaded for this application.
|
20
20
|
def library_pb_list
|
21
|
-
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless ::Contrast::INVENTORY.
|
22
|
-
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless ::Contrast::INVENTORY.analyze_libraries
|
21
|
+
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless ::Contrast::INVENTORY.enable
|
22
|
+
return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless ::Contrast::INVENTORY.analyze_libraries
|
23
23
|
|
24
24
|
loaded_specs.each_with_object([]) do |(_name, spec), reported_lib_list|
|
25
25
|
next unless spec
|
@@ -111,7 +111,7 @@ module Contrast
|
|
111
111
|
|
112
112
|
# We only use this if inventory and library analysis are enabled
|
113
113
|
def enabled?
|
114
|
-
@_enabled = ::Contrast::INVENTORY.
|
114
|
+
@_enabled = ::Contrast::INVENTORY.enable && ::Contrast::INVENTORY.analyze_libraries if @_enabled.nil?
|
115
115
|
@_enabled
|
116
116
|
end
|
117
117
|
end
|
@@ -21,7 +21,7 @@ module Contrast
|
|
21
21
|
DATA_STORE_MARKER = 'data_store'
|
22
22
|
|
23
23
|
def report_data_store _method, _exception, properties, object, _args
|
24
|
-
return unless ::Contrast::INVENTORY.
|
24
|
+
return unless ::Contrast::INVENTORY.enable
|
25
25
|
|
26
26
|
marker = properties[DATA_STORE_MARKER]
|
27
27
|
return unless marker
|
@@ -17,9 +17,9 @@ module Contrast
|
|
17
17
|
#
|
18
18
|
# @param method_policy [Hash]
|
19
19
|
# {
|
20
|
-
# source_node [ Contrast::Agent::
|
21
|
-
# propagation_node [ Contrast::Agent::
|
22
|
-
# trigger_node [ Contrast::Agent::
|
20
|
+
# source_node [ Contrast::Agent::Assess::Policy::SourceNode ]
|
21
|
+
# propagation_node [ Contrast::Agent::Assess::Policy::PropagationNode ]
|
22
|
+
# trigger_node [ Contrast::Agent::Assess::Policy::TriggerNode ]
|
23
23
|
# inventory_node [ Contrast::Agent::Inventory::Policy::TriggerNode ]
|
24
24
|
# protect_node [ Contrast::Agent::Protect::Policy::TriggerNode ]
|
25
25
|
# deadzone_node [ Contrast::Agent::Deadzone::Policy::DeadzoneNode ]
|
@@ -3,7 +3,6 @@
|
|
3
3
|
|
4
4
|
require 'contrast/agent/worker_thread'
|
5
5
|
require 'contrast/agent/reporting/report'
|
6
|
-
require 'contrast/components/logger'
|
7
6
|
require 'contrast/agent/inventory/dependency_usage_analysis'
|
8
7
|
require 'contrast/agent/reporting/reporting_events/poll'
|
9
8
|
require 'contrast/agent/reporting/reporting_events/server_activity'
|
@@ -14,8 +13,6 @@ module Contrast
|
|
14
13
|
# reach out to get the latest settings for this application. It also sends out those messages which do not need to
|
15
14
|
# be associated directly with a request, such as Server Activity and Library Observation.
|
16
15
|
class ReporterHeartbeat < WorkerThread
|
17
|
-
include Contrast::Components::Logger::InstanceMethods
|
18
|
-
|
19
16
|
# TeamServer will mark an application offline after 5 minutes. Sending this every one should be more than enough
|
20
17
|
# to satisfy our goals.
|
21
18
|
REFRESH_INTERVAL_SEC = 60
|
@@ -29,6 +26,7 @@ module Contrast
|
|
29
26
|
polling_events.each do |event|
|
30
27
|
Contrast::Agent.reporter&.send_event(event)
|
31
28
|
end
|
29
|
+
clean_properties
|
32
30
|
sleep(REFRESH_INTERVAL_SEC)
|
33
31
|
end
|
34
32
|
end
|
@@ -56,35 +56,31 @@ module Contrast
|
|
56
56
|
# @param attacker_activity [Contrast::Agent::Reporting::ApplicationDefendAttackerActivity]
|
57
57
|
# @param rule [String]
|
58
58
|
def attach_existing existing_attacker_activity, attacker_activity, rule
|
59
|
-
# TODO: RUBY-1663 figure out attack time mapping
|
60
59
|
new_violation = attacker_activity.protection_rules[rule]
|
60
|
+
sample_activity = Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity
|
61
61
|
if (previously_violated = existing_attacker_activity.protection_rules[rule])
|
62
|
-
if (new_blocked = new_violation.blocked
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
previously_violated.blocked.samples.concat(new_blocked)
|
62
|
+
if (new_blocked = new_violation.blocked)
|
63
|
+
previously_violated.blocked ||= sample_activity.new
|
64
|
+
previously_violated.blocked.samples.concat(new_blocked.samples) if new_blocked.samples
|
65
|
+
previously_violated.blocked.merge_time_maps(new_blocked.time_map)
|
67
66
|
end
|
68
67
|
|
69
|
-
if (new_exploited = new_violation.exploited
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
previously_violated.exploited.samples.concat(new_exploited)
|
68
|
+
if (new_exploited = new_violation.exploited)
|
69
|
+
previously_violated.exploited ||= sample_activity.new
|
70
|
+
previously_violated.exploited.samples.concat(new_exploited.samples) if new_exploited.samples
|
71
|
+
previously_violated.exploited.merge_time_maps(new_exploited.time_map)
|
74
72
|
end
|
75
73
|
|
76
|
-
if (new_ineffective = new_violation.ineffective
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
previously_violated.ineffective.samples.concat(new_ineffective)
|
74
|
+
if (new_ineffective = new_violation.ineffective)
|
75
|
+
previously_violated.ineffective ||= sample_activity.new
|
76
|
+
previously_violated.ineffective.samples.concat(new_ineffective.samples) if new_ineffective.samples
|
77
|
+
previously_violated.ineffective.merge_time_maps(new_ineffective.time_map)
|
81
78
|
end
|
82
79
|
|
83
|
-
if (new_suspicious = new_violation.suspicious
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
previously_violated.suspicious.samples.concat(new_suspicious)
|
80
|
+
if (new_suspicious = new_violation.suspicious)
|
81
|
+
previously_violated.suspicious ||= sample_activity.new
|
82
|
+
previously_violated.suspicious.samples.concat(new_suspicious.samples) if new_suspicious.samples
|
83
|
+
previously_violated.suspicious.merge_time_maps(new_suspicious.time_map)
|
88
84
|
end
|
89
85
|
else
|
90
86
|
existing_attacker_activity.protection_rules[rule] = new_violation
|
data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require 'contrast/components/logger'
|
5
|
+
require 'contrast/utils/timer'
|
5
6
|
require 'contrast/agent/reporting/reporting_events/application_defend_attack_sample'
|
6
7
|
|
7
8
|
module Contrast
|
@@ -26,7 +27,7 @@ module Contrast
|
|
26
27
|
|
27
28
|
def initialize
|
28
29
|
@samples = []
|
29
|
-
@start_time =
|
30
|
+
@start_time = Contrast::Agent::REQUEST_TRACKER.current&.timer&.start_ms || 0 # in ms
|
30
31
|
@event_type = :application_defend_attack_sample_activity
|
31
32
|
@time_map = Hash.new { |h, k| h[k] = 0 }
|
32
33
|
super
|
@@ -36,7 +37,7 @@ module Contrast
|
|
36
37
|
{
|
37
38
|
attackTimeMap: time_map,
|
38
39
|
samples: samples.map(&:to_controlled_hash),
|
39
|
-
startTime: @start_time,
|
40
|
+
startTime: @start_time, # Start time in ms.
|
40
41
|
total: 1 # there will only ever be 1 attack sample, until batching is done
|
41
42
|
}
|
42
43
|
end
|
@@ -44,12 +45,34 @@ module Contrast
|
|
44
45
|
# @param attack_result [Contrast::Api::Dtm::AttackResult]
|
45
46
|
def attach_data attack_result
|
46
47
|
attack_result.samples.each do |attack_sample|
|
48
|
+
base_time = Contrast::Agent::REQUEST_TRACKER.current&.timer&.start_ms || 0
|
49
|
+
dmt_time = attack_sample.timestamp_ms.to_i
|
47
50
|
converted = Contrast::Agent::Reporting::ApplicationDefendAttackSample.convert(attack_result, attack_sample)
|
48
51
|
samples << converted
|
49
|
-
|
52
|
+
@start_time = if dmt_time.zero?
|
53
|
+
@start_time
|
54
|
+
else
|
55
|
+
dmt_time
|
56
|
+
end
|
57
|
+
attack_second = (@start_time - base_time) / 1000 # in seconds
|
50
58
|
time_map[attack_second] += 1
|
51
59
|
end
|
52
60
|
end
|
61
|
+
|
62
|
+
# This method will merge time_maps of attack samples with same
|
63
|
+
# type.
|
64
|
+
#
|
65
|
+
# @param map [Hash<Integer,Integer>] TimeMap to append to previously_violated rule
|
66
|
+
# samples.
|
67
|
+
# @return time_map [Hash<Integer,Integer>] merged time map with updated occurrences.
|
68
|
+
def merge_time_maps map
|
69
|
+
# If the second is the same (key) if we just merge there won't be a new entry,
|
70
|
+
# so just increase the attack count.
|
71
|
+
map.each_key do |key|
|
72
|
+
@time_map[key] = @time_map.fetch(key, 0) + map[key]
|
73
|
+
end
|
74
|
+
@time_map
|
75
|
+
end
|
53
76
|
end
|
54
77
|
end
|
55
78
|
end
|
@@ -26,12 +26,12 @@ module Contrast
|
|
26
26
|
# event field of Contrast::Agent::Reporting::ReportingEvent
|
27
27
|
# @param response_data [Net::HTTP::Response]
|
28
28
|
def audit_event event, response_data = nil
|
29
|
-
return unless ::Contrast::API.request_audit_requests
|
29
|
+
return unless ::Contrast::API.request_audit_requests || ::Contrast::API.request_audit_responses
|
30
30
|
|
31
31
|
file_name = event.cs__respond_to?(:file_name) ? event.file_name : event.cs__class.cs__name.to_s.downcase
|
32
32
|
data = event.to_controlled_hash.to_json
|
33
33
|
log_data(:request, file_name, data) if data
|
34
|
-
return unless ::Contrast::API.request_audit_responses
|
34
|
+
return unless ::Contrast::API.request_audit_responses
|
35
35
|
|
36
36
|
data = response_data&.body || 'There is no available response'
|
37
37
|
log_data(:response, file_name, data)
|
@@ -94,7 +94,7 @@ module Contrast
|
|
94
94
|
# Retrieves the configuration value if the request audit is enabled
|
95
95
|
# @return [Boolean]
|
96
96
|
def enabled?
|
97
|
-
::Contrast::API.request_audit_enable
|
97
|
+
::Contrast::API.request_audit_enable
|
98
98
|
end
|
99
99
|
|
100
100
|
# The boolean values for the requests and the responses should be taken under
|
@@ -107,13 +107,13 @@ module Contrast
|
|
107
107
|
# Retrieve the configuration value if the audit for requests is enabled
|
108
108
|
# @return [Boolean]
|
109
109
|
def enabled_for_requests?
|
110
|
-
::Contrast::API.request_audit_requests
|
110
|
+
::Contrast::API.request_audit_requests
|
111
111
|
end
|
112
112
|
|
113
113
|
# Retrieve the configuration value if the audit for responses is enabled
|
114
114
|
# @return [Boolean]
|
115
115
|
def enabled_for_responses?
|
116
|
-
::Contrast::API.request_audit_requests
|
116
|
+
::Contrast::API.request_audit_requests
|
117
117
|
end
|
118
118
|
|
119
119
|
# Retrieve the configuration value for the path of the audits
|
@@ -24,7 +24,7 @@ module Contrast
|
|
24
24
|
@app_language = RUBY
|
25
25
|
@app_path = Base64.strict_encode64(Contrast::APP_CONTEXT.path)
|
26
26
|
@app_version = Contrast::APP_CONTEXT.app_version
|
27
|
-
@authorization = Base64.strict_encode64("#{ Contrast::API.
|
27
|
+
@authorization = Base64.strict_encode64("#{ Contrast::API.user_name }:#{ Contrast::API.service_key }")
|
28
28
|
@server_name = Base64.strict_encode64(Contrast::APP_CONTEXT.server_name)
|
29
29
|
@server_path = Base64.strict_encode64(Contrast::APP_CONTEXT.server_path)
|
30
30
|
@server_type = Base64.strict_encode64(Contrast::APP_CONTEXT.server_type)
|
@@ -59,7 +59,7 @@ module Contrast
|
|
59
59
|
|
60
60
|
request = build_request(event)
|
61
61
|
response = connection.request(request)
|
62
|
-
audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable
|
62
|
+
audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable
|
63
63
|
process_settings_response(response)
|
64
64
|
process_preflight_response(event, response, connection)
|
65
65
|
response
|
@@ -185,7 +185,7 @@ module Contrast
|
|
185
185
|
::Contrast::SETTINGS.build_protect_rules if ::Contrast::PROTECT.enabled?
|
186
186
|
::Contrast::AGENT.reset_ruleset
|
187
187
|
logger.info('Current rule settings:')
|
188
|
-
::Contrast::PROTECT.
|
188
|
+
::Contrast::PROTECT.defend_rules.each { |k, v| logger.info('Protect Rule mode set', rule: k, mode: v.mode) }
|
189
189
|
logger.info('Disabled Assess Rules', rules: ::Contrast::ASSESS.disabled_rules)
|
190
190
|
end
|
191
191
|
end
|
@@ -43,6 +43,8 @@ module Contrast
|
|
43
43
|
# @return [Contrast::Utils::Timer] when the context was created
|
44
44
|
attr_reader :timer
|
45
45
|
|
46
|
+
attr_accessor :propagation_event_count, :source_event_count
|
47
|
+
|
46
48
|
def initialize rack_request, app_loaded: true
|
47
49
|
with_contrast_scope do
|
48
50
|
# all requests get a timer and hash
|
@@ -68,6 +70,12 @@ module Contrast
|
|
68
70
|
# generic holder for properties that can be set throughout this request
|
69
71
|
@_properties = {}
|
70
72
|
|
73
|
+
# count of propagation events
|
74
|
+
@propagation_event_count = 0
|
75
|
+
|
76
|
+
# count of source events
|
77
|
+
@source_event_count = 0
|
78
|
+
|
71
79
|
if ::Contrast::ASSESS.enabled?
|
72
80
|
@sample_req, @sample_res = Contrast::Utils::Assess::SamplingUtil.instance.sample?(@request)
|
73
81
|
end
|
@@ -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/components/logger'
|
5
4
|
require 'contrast/agent/worker_thread'
|
6
5
|
require 'contrast/agent/reporting/report'
|
7
6
|
|
@@ -10,8 +9,6 @@ module Contrast
|
|
10
9
|
# The ServiceHeartbeat functions to keep the Contrast Service alive and ensure that it maintains this Agent's
|
11
10
|
# ApplicationContext.
|
12
11
|
class ServiceHeartbeat < WorkerThread
|
13
|
-
include Contrast::Components::Logger::InstanceMethods
|
14
|
-
|
15
12
|
# Spec recommends 30 seconds, we're going with 15.
|
16
13
|
REFRESH_INTERVAL_SEC = 15
|
17
14
|
|
@@ -22,7 +19,9 @@ module Contrast
|
|
22
19
|
@_thread = Contrast::Agent::Thread.new do
|
23
20
|
logger.info('Starting heartbeat thread.')
|
24
21
|
loop do
|
22
|
+
logger.info("Queue Size: #{ Contrast::Agent.messaging_queue.queue&.length }")
|
25
23
|
Contrast::Agent.messaging_queue&.send_event_eventually(poll_message)
|
24
|
+
clean_properties
|
26
25
|
sleep(REFRESH_INTERVAL_SEC)
|
27
26
|
end
|
28
27
|
end
|
@@ -24,7 +24,7 @@ module Contrast
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def send_inventory_message
|
27
|
-
return unless ::Contrast::INVENTORY.
|
27
|
+
return unless ::Contrast::INVENTORY.enable
|
28
28
|
|
29
29
|
report = Contrast::Agent::Reporting::ApplicationUpdate.new
|
30
30
|
# This convert here is left as it'll be easier to be replaced when the Library is being changed
|