contrast-agent 6.0.0 → 6.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (260) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +1 -1
  3. data/Rakefile +1 -1
  4. data/ext/build_funchook.rb +3 -3
  5. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +5 -1
  6. data/ext/cs__assess_regexp/cs__assess_regexp.c +15 -2
  7. data/ext/cs__assess_regexp/cs__assess_regexp.h +2 -0
  8. data/ext/cs__assess_string/cs__assess_string.c +8 -0
  9. data/ext/cs__assess_test/cs__assess_test.h +9 -0
  10. data/ext/cs__assess_test/cs__assess_tests.c +22 -0
  11. data/ext/cs__assess_test/extconf.rb +5 -0
  12. data/ext/cs__common/cs__common.c +101 -0
  13. data/ext/cs__common/cs__common.h +29 -5
  14. data/ext/cs__contrast_patch/cs__contrast_patch.c +1 -1
  15. data/ext/cs__tests/cs__tests.c +12 -0
  16. data/ext/cs__tests/cs__tests.h +3 -0
  17. data/ext/cs__tests/extconf.rb +5 -0
  18. data/ext/extconf_common.rb +1 -1
  19. data/lib/contrast/agent/assess/contrast_object.rb +16 -16
  20. data/lib/contrast/agent/assess/events/source_event.rb +17 -19
  21. data/lib/contrast/agent/assess/finalizers/hash.rb +2 -2
  22. data/lib/contrast/agent/assess/policy/policy.rb +9 -10
  23. data/lib/contrast/agent/assess/policy/policy_node.rb +9 -10
  24. data/lib/contrast/agent/assess/policy/policy_scanner.rb +2 -16
  25. data/lib/contrast/agent/assess/policy/propagation_method.rb +3 -3
  26. data/lib/contrast/agent/assess/policy/propagation_node.rb +2 -3
  27. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  28. data/lib/contrast/agent/assess/policy/propagator/buffer.rb +2 -1
  29. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +1 -1
  30. data/lib/contrast/agent/assess/policy/propagator/splat.rb +1 -1
  31. data/lib/contrast/agent/assess/policy/propagator/split.rb +17 -21
  32. data/lib/contrast/agent/assess/policy/propagator/trim.rb +1 -1
  33. data/lib/contrast/agent/assess/policy/source_node.rb +1 -1
  34. data/lib/contrast/agent/assess/policy/trigger_method.rb +10 -18
  35. data/lib/contrast/agent/assess/policy/trigger_node.rb +16 -16
  36. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +1 -1
  37. data/lib/contrast/agent/assess/property/evented.rb +2 -2
  38. data/lib/contrast/agent/assess/property/tagged.rb +2 -2
  39. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +6 -8
  40. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +6 -7
  41. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +12 -7
  42. data/lib/contrast/agent/assess/rule/response/base_rule.rb +13 -6
  43. data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +66 -43
  44. data/lib/contrast/agent/assess/rule/response/click_jacking_header_rule.rb +4 -4
  45. data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +6 -6
  46. data/lib/contrast/agent/assess/rule/response/csp_header_missing_rule.rb +4 -4
  47. data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +4 -4
  48. data/lib/contrast/agent/assess/rule/response/x_content_type_header_rule.rb +4 -4
  49. data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +3 -4
  50. data/lib/contrast/agent/assess/tag.rb +13 -14
  51. data/lib/contrast/agent/at_exit_hook.rb +12 -1
  52. data/lib/contrast/agent/inventory/database_config.rb +22 -7
  53. data/lib/contrast/agent/middleware.rb +9 -6
  54. data/lib/contrast/agent/patching/policy/after_load_patch.rb +3 -5
  55. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +2 -2
  56. data/lib/contrast/agent/patching/policy/method_policy_extend.rb +4 -4
  57. data/lib/contrast/agent/patching/policy/patch.rb +20 -19
  58. data/lib/contrast/agent/patching/policy/patch_status.rb +10 -3
  59. data/lib/contrast/agent/patching/policy/patcher.rb +1 -1
  60. data/lib/contrast/agent/patching/policy/policy.rb +13 -15
  61. data/lib/contrast/agent/patching/policy/policy_node.rb +19 -21
  62. data/lib/contrast/agent/patching/policy/trigger_node.rb +1 -1
  63. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +126 -122
  64. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +2 -2
  65. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -1
  66. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +1 -1
  67. data/lib/contrast/agent/protect/policy/rule_applicator.rb +4 -4
  68. data/lib/contrast/agent/protect/rule/base.rb +30 -18
  69. data/lib/contrast/agent/protect/rule/base_service.rb +31 -14
  70. data/lib/contrast/agent/protect/rule/cmd_injection.rb +16 -9
  71. data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +3 -3
  72. data/lib/contrast/agent/protect/rule/default_scanner.rb +2 -1
  73. data/lib/contrast/agent/protect/rule/deserialization.rb +18 -7
  74. data/lib/contrast/agent/protect/rule/http_method_tampering/http_method_tampering_input_classification.rb +74 -74
  75. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +71 -53
  76. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +3 -3
  77. data/lib/contrast/agent/protect/rule/no_sqli.rb +15 -16
  78. data/lib/contrast/agent/protect/rule/path_traversal.rb +13 -3
  79. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +2 -2
  80. data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +1 -1
  81. data/lib/contrast/agent/protect/rule/sqli.rb +16 -23
  82. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +61 -61
  83. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_matcher.rb +29 -29
  84. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +32 -32
  85. data/lib/contrast/agent/protect/rule/xss.rb +17 -0
  86. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +14 -13
  87. data/lib/contrast/agent/protect/rule/xxe.rb +25 -3
  88. data/lib/contrast/agent/reaction_processor.rb +1 -1
  89. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +36 -36
  90. data/lib/contrast/agent/reporting/masker/masker.rb +18 -21
  91. data/lib/contrast/agent/reporting/masker/masker_utils.rb +10 -6
  92. data/lib/contrast/agent/reporting/reporter.rb +11 -16
  93. data/lib/contrast/agent/reporting/reporter_heartbeat.rb +49 -0
  94. data/lib/contrast/agent/reporting/reporting_events/agent_startup.rb +6 -2
  95. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +51 -0
  96. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +96 -0
  97. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +70 -0
  98. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +182 -0
  99. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity.rb +56 -0
  100. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample_stack.rb +22 -0
  101. data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +70 -0
  102. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +6 -2
  103. data/lib/contrast/agent/reporting/reporting_events/application_inventory_activity.rb +60 -0
  104. data/lib/contrast/agent/reporting/reporting_events/application_reporting_event.rb +27 -0
  105. data/lib/contrast/agent/reporting/reporting_events/application_startup.rb +15 -11
  106. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +7 -12
  107. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +1 -1
  108. data/lib/contrast/agent/reporting/reporting_events/finding.rb +9 -3
  109. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +2 -4
  110. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +3 -3
  111. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +6 -2
  112. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +7 -3
  113. data/lib/contrast/agent/reporting/reporting_events/poll.rb +6 -2
  114. data/lib/contrast/agent/reporting/reporting_events/preflight.rb +10 -8
  115. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +6 -10
  116. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +12 -20
  117. data/lib/contrast/agent/reporting/reporting_events/server_reporting_event.rb +27 -0
  118. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +17 -27
  119. data/lib/contrast/agent/reporting/reporting_utilities/build_preflight.rb +38 -0
  120. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +8 -0
  121. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +6 -0
  122. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +1 -2
  123. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +15 -10
  124. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +54 -67
  125. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +17 -7
  126. data/lib/contrast/agent/reporting/reporting_utilities/response_extractor.rb +9 -6
  127. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +17 -17
  128. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +47 -32
  129. data/lib/contrast/agent/reporting/settings/application_settings.rb +1 -1
  130. data/lib/contrast/agent/reporting/settings/assess.rb +5 -5
  131. data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +3 -3
  132. data/lib/contrast/agent/reporting/settings/exclusions.rb +3 -3
  133. data/lib/contrast/agent/reporting/settings/protect.rb +21 -6
  134. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +6 -6
  135. data/lib/contrast/agent/reporting/settings/reaction.rb +3 -3
  136. data/lib/contrast/agent/reporting/settings/sensitive_data_masking.rb +2 -2
  137. data/lib/contrast/agent/reporting/settings/sensitive_data_masking_rule.rb +2 -2
  138. data/lib/contrast/agent/reporting/settings/server_features.rb +2 -2
  139. data/lib/contrast/agent/request.rb +5 -5
  140. data/lib/contrast/agent/request_context.rb +23 -19
  141. data/lib/contrast/agent/request_context_extend.rb +11 -24
  142. data/lib/contrast/agent/request_handler.rb +4 -4
  143. data/lib/contrast/agent/response.rb +2 -0
  144. data/lib/contrast/agent/rule_set.rb +2 -2
  145. data/lib/contrast/agent/scope.rb +1 -1
  146. data/lib/contrast/agent/service_heartbeat.rb +6 -48
  147. data/lib/contrast/agent/static_analysis.rb +1 -1
  148. data/lib/contrast/agent/telemetry/base.rb +155 -0
  149. data/lib/contrast/agent/telemetry/events/event.rb +35 -0
  150. data/lib/contrast/agent/telemetry/events/exceptions/obfuscate.rb +119 -0
  151. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_base.rb +44 -36
  152. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_event.rb +29 -21
  153. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message.rb +91 -73
  154. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_message_exception.rb +62 -44
  155. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exception_stack_frame.rb +50 -33
  156. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions.rb +20 -0
  157. data/lib/contrast/agent/telemetry/events/exceptions/telemetry_exceptions_report.rb +30 -0
  158. data/lib/contrast/agent/telemetry/events/metric_event.rb +28 -0
  159. data/lib/contrast/agent/telemetry/events/startup_metrics_event.rb +123 -0
  160. data/lib/contrast/agent/thread_watcher.rb +52 -68
  161. data/lib/contrast/agent/version.rb +1 -1
  162. data/lib/contrast/agent/worker_thread.rb +8 -0
  163. data/lib/contrast/agent.rb +1 -3
  164. data/lib/contrast/api/communication/messaging_queue.rb +29 -12
  165. data/lib/contrast/api/communication/response_processor.rb +7 -10
  166. data/lib/contrast/api/communication/service_lifecycle.rb +1 -1
  167. data/lib/contrast/api/communication/socket.rb +1 -1
  168. data/lib/contrast/api/communication/socket_client.rb +1 -1
  169. data/lib/contrast/api/communication/speedracer.rb +3 -3
  170. data/lib/contrast/api/decorators/activity.rb +33 -0
  171. data/lib/contrast/api/decorators/agent_startup.rb +10 -9
  172. data/lib/contrast/api/decorators/application_settings.rb +1 -1
  173. data/lib/contrast/api/decorators/application_startup.rb +4 -4
  174. data/lib/contrast/api/decorators/http_request.rb +1 -1
  175. data/lib/contrast/api/decorators/response_type.rb +4 -17
  176. data/lib/contrast/components/agent.rb +1 -1
  177. data/lib/contrast/components/base.rb +1 -1
  178. data/lib/contrast/components/config.rb +19 -28
  179. data/lib/contrast/components/contrast_service.rb +13 -1
  180. data/lib/contrast/components/sampling.rb +1 -1
  181. data/lib/contrast/components/settings.rb +58 -24
  182. data/lib/contrast/config/agent_configuration.rb +21 -11
  183. data/lib/contrast/config/api_configuration.rb +12 -8
  184. data/lib/contrast/config/api_proxy_configuration.rb +7 -3
  185. data/lib/contrast/config/application_configuration.rb +15 -11
  186. data/lib/contrast/config/assess_configuration.rb +13 -9
  187. data/lib/contrast/config/assess_rules_configuration.rb +6 -2
  188. data/lib/contrast/config/base_configuration.rb +3 -35
  189. data/lib/contrast/config/certification_configuration.rb +9 -5
  190. data/lib/contrast/config/exception_configuration.rb +10 -7
  191. data/lib/contrast/config/heap_dump_configuration.rb +13 -9
  192. data/lib/contrast/config/inventory_configuration.rb +9 -6
  193. data/lib/contrast/config/logger_configuration.rb +9 -6
  194. data/lib/contrast/config/protect_configuration.rb +9 -6
  195. data/lib/contrast/config/protect_rule_configuration.rb +12 -8
  196. data/lib/contrast/config/protect_rules_configuration.rb +19 -18
  197. data/lib/contrast/config/request_audit_configuration.rb +10 -7
  198. data/lib/contrast/config/root_configuration.rb +29 -12
  199. data/lib/contrast/config/ruby_configuration.rb +14 -11
  200. data/lib/contrast/config/sampling_configuration.rb +11 -8
  201. data/lib/contrast/config/server_configuration.rb +13 -9
  202. data/lib/contrast/config/service_configuration.rb +14 -11
  203. data/lib/contrast/configuration.rb +23 -14
  204. data/lib/contrast/extension/assess/array.rb +1 -1
  205. data/lib/contrast/extension/assess/erb.rb +1 -1
  206. data/lib/contrast/extension/assess/marshal.rb +1 -1
  207. data/lib/contrast/extension/assess/string.rb +1 -1
  208. data/lib/contrast/extension/extension.rb +2 -2
  209. data/lib/contrast/framework/base_support.rb +8 -8
  210. data/lib/contrast/framework/grape/support.rb +3 -3
  211. data/lib/contrast/framework/manager.rb +5 -5
  212. data/lib/contrast/framework/manager_extend.rb +1 -1
  213. data/lib/contrast/framework/rack/patch/session_cookie.rb +1 -1
  214. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +14 -3
  215. data/lib/contrast/framework/rails/patch/assess_configuration.rb +3 -3
  216. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +1 -1
  217. data/lib/contrast/framework/rails/patch/support.rb +14 -46
  218. data/lib/contrast/framework/rails/support.rb +2 -2
  219. data/lib/contrast/framework/sinatra/support.rb +1 -1
  220. data/lib/contrast/logger/aliased_logging.rb +94 -0
  221. data/lib/contrast/logger/application.rb +0 -4
  222. data/lib/contrast/logger/cef_log.rb +14 -14
  223. data/lib/contrast/logger/format.rb +1 -1
  224. data/lib/contrast/logger/log.rb +8 -8
  225. data/lib/contrast/tasks/config.rb +30 -21
  226. data/lib/contrast/tasks/service.rb +2 -2
  227. data/lib/contrast/utils/assess/tracking_util.rb +4 -4
  228. data/lib/contrast/utils/class_util.rb +6 -10
  229. data/lib/contrast/utils/findings.rb +3 -3
  230. data/lib/contrast/utils/hash_digest.rb +6 -7
  231. data/lib/contrast/utils/head_dump_utils_extend.rb +1 -1
  232. data/lib/contrast/utils/invalid_configuration_util.rb +2 -2
  233. data/lib/contrast/utils/log_utils.rb +6 -4
  234. data/lib/contrast/utils/lru_cache.rb +1 -1
  235. data/lib/contrast/utils/metrics_hash.rb +1 -1
  236. data/lib/contrast/utils/middleware_utils.rb +6 -6
  237. data/lib/contrast/utils/net_http_base.rb +4 -4
  238. data/lib/contrast/utils/object_share.rb +1 -1
  239. data/lib/contrast/utils/os.rb +1 -1
  240. data/lib/contrast/utils/patching/policy/patch_utils.rb +2 -2
  241. data/lib/contrast/utils/request_utils.rb +2 -2
  242. data/lib/contrast/utils/sha256_builder.rb +4 -4
  243. data/lib/contrast/utils/stack_trace_utils.rb +31 -13
  244. data/lib/contrast/utils/telemetry.rb +22 -7
  245. data/lib/contrast/utils/telemetry_client.rb +27 -15
  246. data/lib/contrast/utils/telemetry_hash.rb +41 -0
  247. data/lib/contrast/utils/telemetry_identifier.rb +18 -3
  248. data/lib/contrast/utils/timer.rb +1 -1
  249. data/lib/contrast.rb +9 -0
  250. data/resources/assess/policy.json +1 -1
  251. data/ruby-agent.gemspec +1 -1
  252. data/service_executables/VERSION +1 -1
  253. data/service_executables/linux/contrast-service +0 -0
  254. data/service_executables/mac/contrast-service +0 -0
  255. metadata +41 -16
  256. data/lib/contrast/agent/telemetry/events/metric_telemetry_event.rb +0 -26
  257. data/lib/contrast/agent/telemetry/events/startup_metrics_telemetry_event.rb +0 -121
  258. data/lib/contrast/agent/telemetry/events/telemetry_event.rb +0 -33
  259. data/lib/contrast/agent/telemetry/telemetry.rb +0 -150
  260. data/lib/contrast/utils/exclude_key.rb +0 -20
@@ -33,21 +33,18 @@ module Contrast
33
33
  # @param [Contrast::Api::Dtm::Activity]
34
34
  def mask activity
35
35
  return unless Contrast::Agent::Reporter.enabled?
36
- return unless activity || activity.http_request || activity.results
36
+ return unless activity
37
37
 
38
38
  logger.debug('Searching for sensitive data',
39
39
  activity: activity.__id__,
40
40
  request: activity.http_request&.uuid)
41
- mask_body activity
42
- mask_query_string activity
43
- mask_request_params activity
44
- mask_request_cookies activity
45
- mask_request_headers activity
46
- rescue StandardError => e
47
- logger.debug('Could not mask activity!',
48
- activity: activity.__id__,
49
- request: activity.http_request&.uuid,
50
- error_msg: e.message)
41
+ mask_body(activity)
42
+ mask_query_string(activity)
43
+ mask_request_params(activity)
44
+ mask_request_cookies(activity)
45
+ mask_request_headers(activity)
46
+ rescue StandardError => _e
47
+ logger.debug('Could not mask activity!', activity: activity.__id__, request: activity.http_request&.uuid)
51
48
  end
52
49
 
53
50
  private
@@ -87,16 +84,16 @@ module Contrast
87
84
  params = activity.http_request.normalized_request_params
88
85
  return unless params
89
86
 
90
- mask_with_dictionary activity.results, params
87
+ mask_with_dictionary(activity.results, params)
91
88
  end
92
89
 
93
90
  def mask_request_headers activity
94
91
  if activity.http_request.parsed_request_headers
95
92
  # Used normalized request_headers
96
- mask_with_dictionary activity.results, activity.http_request.normalized_request_headers
93
+ mask_with_dictionary(activity.results, activity.http_request.normalized_request_headers)
97
94
  else
98
95
  headers = activity.http_request.request_headers
99
- mask_field_hash headers, activity.results
96
+ mask_field_hash(headers, activity.results)
100
97
  end
101
98
  end
102
99
 
@@ -108,7 +105,7 @@ module Contrast
108
105
  cookies = activity.http_request.normalized_cookies
109
106
  return unless cookies
110
107
 
111
- mask_with_dictionary activity.results, cookies
108
+ mask_with_dictionary(activity.results, cookies)
112
109
  end
113
110
 
114
111
  # Mask request query string:
@@ -120,8 +117,8 @@ module Contrast
120
117
  qs = activity.http_request.query_string
121
118
  return if qs.nil? || qs.empty?
122
119
 
123
- mask_field_hash qs, activity.results unless qs.cs__is_a?(String)
124
- mask_raw_query qs, activity.results
120
+ mask_field_hash(qs, activity.results) unless qs.cs__is_a?(String)
121
+ mask_raw_query(qs, activity.results)
125
122
  end
126
123
 
127
124
  # Mask if the value in the passed hash are matched against dictionary
@@ -137,17 +134,17 @@ module Contrast
137
134
  return if hash.nil? || hash.empty?
138
135
 
139
136
  hash.each do |key, val|
140
- match = dictionary_matcher key
137
+ match = dictionary_matcher(key)
141
138
  next unless match
142
139
 
143
140
  # The normalized values are paired.
144
141
  # key => Contrast::Api::Dtm::Pair (key, val<Values>).
145
142
  # try one level down
146
- if val.cs__respond_to? :values
147
- mask_values key, val, results
143
+ if val.cs__respond_to?(:values)
144
+ mask_values(key, val, results)
148
145
  else
149
146
  # Just assign keys.
150
- mask_hash key, val, hash, results
147
+ mask_hash(key, val, hash, results)
151
148
  end
152
149
  end
153
150
  hash
@@ -14,10 +14,14 @@ module Contrast
14
14
  # @param field_hash [Protobuf::Field::FieldHash] hash to be masked
15
15
  # @param results [Array<Contrast::Api::Dtm::AttackResults>]
16
16
  # results to match against.
17
+ # @return [Hash]
17
18
  def mask_field_hash field_hash, results
19
+ return {} unless field_hash&.any?
20
+
18
21
  hash = {}
19
- masked = EMPTY_STRING
20
- field_hash.any? do |entry|
22
+ # Because this is the start of a built string, we have to be sure that it is not frozen.
23
+ masked = +''
24
+ field_hash.each do |entry|
21
25
  # Protobuf::Field::FieldHash produces array, with the key as first param and value as second.
22
26
  new_value = entry[1].delete(SEMICOLON).split(SPACE)
23
27
  new_value.each do |value|
@@ -26,10 +30,10 @@ module Contrast
26
30
  hash[arr[0]] = arr[1]
27
31
  end
28
32
  # Mask the newly created hash.
29
- mask_with_dictionary results, hash
33
+ mask_with_dictionary(results, hash)
30
34
 
31
35
  # Restore to original form.
32
- hash.each { |k, v| masked += "#{ k + EQUALS }#{ v + SEMICOLON + SPACE }" }
36
+ hash.each { |k, v| masked += "#{ k }=#{ v }; " }
33
37
  masked.rstrip!
34
38
  field_hash[entry[0]] = masked
35
39
  end
@@ -46,9 +50,9 @@ module Contrast
46
50
  def mask_raw_query query, results
47
51
  masked = EMPTY_STRING
48
52
  hash = URI.decode_www_form(query).to_h
49
- mask_with_dictionary results, hash
53
+ mask_with_dictionary(results, hash)
50
54
  # Restore to string form.
51
- hash.each { |k, v| masked += "#{ k + EQUALS }#{ v }#{ AMPERSAND }" }
55
+ hash.each { |k, v| masked += "#{ k }=#{ v }&" }
52
56
  query = masked
53
57
  query.chomp!(masked[-1])
54
58
  end
@@ -31,10 +31,6 @@ module Contrast
31
31
  @_connection ||= client.initialize_connection
32
32
  end
33
33
 
34
- def audit
35
- @_audit ||= Contrast::Agent::Reporting::Audit.new
36
- end
37
-
38
34
  def attempt_to_start?
39
35
  unless cs__class.enabled?
40
36
  logger.warn('Reporter service is disabled!')
@@ -65,7 +61,7 @@ module Contrast
65
61
  # Suspend the Reporter and try sending the event after the timeout.
66
62
  # The timeout is either default 15 min or received via TS response.
67
63
  #
68
- # @param event [Contrast::Agent::Reporting::FindingEvent] Freshly pop-ed event.
64
+ # @param event [Contrast::Agent::Reporting::ReportingEvent] Freshly pop-ed event.
69
65
  def handle_resend event
70
66
  sleep(client.timeout) if client.sleep?
71
67
  # Retry once than discard the event. This is trigger on too many events of
@@ -75,6 +71,7 @@ module Contrast
75
71
  client.wake_up
76
72
  end
77
73
 
74
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
78
75
  def send_event event
79
76
  if ::Contrast::AGENT.disabled?
80
77
  logger.warn('Attempted to queue event with Agent disabled', caller: caller, event: event)
@@ -84,23 +81,21 @@ module Contrast
84
81
  return unless cs__class.enabled?
85
82
 
86
83
  logger.debug('Enqueued event for sending', event_type: event.cs__class)
87
- audit&.audit_event(event) if ::Contrast::API.request_audit_enable?
88
84
  queue << event
89
85
  end
90
86
 
91
87
  # Use this to bypass the messaging queue and leave response processing to the caller
88
+ #
89
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
90
+ # @return [Net::HTTPResponse, nil]
92
91
  def send_event_immediately event
93
92
  if ::Contrast::AGENT.disabled?
94
93
  logger.warn('Reporter attempted to send event immediately with Agent disabled', caller: caller, event: event)
95
94
  return
96
95
  end
97
- response = client.send_event(event, connection, true)
98
- return unless response
99
-
100
- client.handle_response(event, response, connection)
101
- audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable?
96
+ client.send_event(event, connection, send_immediately: true)
102
97
  rescue StandardError => e
103
- logger.error('Could not send message to service from Reporter queue.', e)
98
+ logger.error('Could not send message to TeamServer from Reporter queue.', e)
104
99
  end
105
100
 
106
101
  def delete_queue!
@@ -122,12 +117,12 @@ module Contrast
122
117
  @_queue ||= Queue.new
123
118
  end
124
119
 
120
+ # @param event [Contrast::Agent::Reporting::ReportingEvent]
125
121
  def process_event event
126
- response = client.send_event(event, connection)
127
- audit&.audit_event(event, response) if ::Contrast::API.request_audit_enable?
128
- handle_resend event
122
+ client.send_event(event, connection)
123
+ handle_resend(event) if client.mode.status == client.mode.resending
129
124
  rescue StandardError => e
130
- logger.error('Could not send message to service from Reporter queue.', e)
125
+ logger.error('Could not send message to TeamServer from Reporter queue.', e)
131
126
  end
132
127
  end
133
128
  end
@@ -0,0 +1,49 @@
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/worker_thread'
5
+ require 'contrast/agent/reporting/report'
6
+ require 'contrast/components/logger'
7
+ require 'contrast/agent/reporting/reporting_events/agent_startup'
8
+
9
+ module Contrast
10
+ module Agent
11
+ # The ReporterHeartbeat will make sure that the process remains marked alive by TeamServer and that we periodically
12
+ # reach out to get the latest settings for this application.
13
+ class ReporterHeartbeat < WorkerThread
14
+ include Contrast::Components::Logger::InstanceMethods
15
+
16
+ # TeamServer will mark an application offline after 5 minutes. Sending this every one should be more than enough
17
+ # to satisfy our goals.
18
+ REFRESH_INTERVAL_SEC = 60
19
+
20
+ # check if we can report to TS
21
+ #
22
+ # @return[Boolean] true if bypass is enabled, or false if bypass disabled
23
+ def enabled?
24
+ @_enabled = Contrast::CONTRAST_SERVICE.use_agent_communication? if @_enabled.nil?
25
+ @_enabled
26
+ end
27
+
28
+ def connection
29
+ @_connection ||= client.initialize_connection
30
+ end
31
+
32
+ def start_thread!
33
+ return if running?
34
+
35
+ @_thread = Contrast::Agent::Thread.new do
36
+ logger.info('Starting heartbeat thread.')
37
+ loop do
38
+ Contrast::Agent.reporter&.send_event(poll_message)
39
+ sleep(REFRESH_INTERVAL_SEC)
40
+ end
41
+ end
42
+ end
43
+
44
+ def poll_message
45
+ @_poll_message ||= Contrast::Agent::Reporting::Poll.new
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,7 +1,7 @@
1
1
  # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'contrast/agent/reporting/reporting_events/reporting_event'
4
+ require 'contrast/agent/reporting/reporting_events/server_reporting_event'
5
5
  require 'contrast/config'
6
6
 
7
7
  module Contrast
@@ -9,7 +9,7 @@ module Contrast
9
9
  module Reporting
10
10
  # AgentStartup Event which sends the agent data to TeamServer on the startup of a server or process,
11
11
  # used to create a new Server entity there.
12
- class AgentStartup < Contrast::Agent::Reporting::ReportingEvent
12
+ class AgentStartup < Contrast::Agent::Reporting::ServerReportingEvent
13
13
  def initialize
14
14
  @event_method = :PUT
15
15
  @event_endpoint = Contrast::Agent::Reporting::Endpoints::NG_ENDPOINTS[:agent_startup]
@@ -17,6 +17,10 @@ module Contrast
17
17
  super
18
18
  end
19
19
 
20
+ def file_name
21
+ 'agent-startup'
22
+ end
23
+
20
24
  def to_controlled_hash
21
25
  {
22
26
  environment: ::Contrast::CONFIG.root.server.environment,
@@ -0,0 +1,51 @@
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/reporting/reporting_events/application_reporting_event'
6
+ require 'contrast/agent/reporting/reporting_events/application_defend_activity'
7
+ require 'contrast/agent/reporting/reporting_events/application_inventory_activity'
8
+
9
+ module Contrast
10
+ module Agent
11
+ module Reporting
12
+ # This is the new ApplicationActivity class which will include all the needed information for the new reporting
13
+ # system to report
14
+ class ApplicationActivity < Contrast::Agent::Reporting::ApplicationReportingEvent
15
+ class << self
16
+ # @param app_activity_dtm [Contrast::Api::Dtm::Activity]
17
+ # @return [Contrast::Agent::Reporting::ApplicationActivity]
18
+ def convert app_activity_dtm
19
+ app_activity = new
20
+ app_activity.attach_data(app_activity_dtm)
21
+ app_activity
22
+ end
23
+ end
24
+
25
+ def initialize
26
+ @event_method = :PUT
27
+ @event_type = :application_activity
28
+ @event_endpoint = Contrast::Agent::Reporting::Endpoints.application_activity
29
+ super
30
+ end
31
+
32
+ def file_name
33
+ 'activity-application'
34
+ end
35
+
36
+ def to_controlled_hash
37
+ hsh = { lastUpdate: since_last_update }
38
+ hsh[:defend] = @defend&.to_controlled_hash if @defend
39
+ hsh[:inventory] = @inventory&.to_controlled_hash if @inventory
40
+ hsh
41
+ end
42
+
43
+ # @param activity_dtm [Contrast::Api::Dtm::ApplicationActivity]
44
+ def attach_data activity_dtm
45
+ @defend = Contrast::Agent::Reporting::ApplicationDefendActivity.convert(activity_dtm)
46
+ @inventory = Contrast::Agent::Reporting::ApplicationInventoryActivity.convert(activity_dtm)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,96 @@
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/reporting/reporting_events/application_defend_attacker_activity'
6
+
7
+ module Contrast
8
+ module Agent
9
+ module Reporting
10
+ # This is the new ApplicationDefendActivity class which includes information about the defense of the application
11
+ # which was discovered during exercise of the application during this activity period.
12
+ class ApplicationDefendActivity
13
+ # @return [Array<Contrast::Agent::Reporting::ApplicationDefendAttackerActivity>]
14
+ attr_reader :attackers
15
+
16
+ class << self
17
+ # @param activity_dtm [Contrast::Api::Dtm::ApplicationActivity]
18
+ # @return [Contrast::Agent::Reporting::ApplicationDefendActivity]
19
+ def convert activity_dtm
20
+ activity = new
21
+ activity.attach_data(activity_dtm.results)
22
+ activity
23
+ end
24
+ end
25
+
26
+ def initialize
27
+ @attackers = []
28
+ @event_type = :application_defend_activity
29
+ super
30
+ end
31
+
32
+ def to_controlled_hash
33
+ {
34
+ attackers: attackers.map(&:to_controlled_hash)
35
+ }
36
+ end
37
+
38
+ # @param attack_dtms [Array<Contrast::Api::Dtm::AttackResult>]
39
+ def attach_data attack_dtms
40
+ attack_dtms.each do |attack_result|
41
+ attacker_activity = Contrast::Agent::Reporting::ApplicationDefendAttackerActivity.convert(attack_result)
42
+ existing_attacker_activity = attackers.find do |existing|
43
+ existing.source_forwarded_for == attacker_activity.source_forwarded_for &&
44
+ existing.source_ip == attacker_activity.source_ip
45
+ end
46
+ rule = attack_result.rule_id
47
+ if existing_attacker_activity
48
+ attach_existing(existing_attacker_activity, attacker_activity, rule)
49
+ else
50
+ attackers << attacker_activity
51
+ end
52
+ end
53
+ end
54
+
55
+ # @param existing_attacker_activity [Contrast::Agent::Reporting::ApplicationDefendAttackerActivity]
56
+ # @param attacker_activity [Contrast::Agent::Reporting::ApplicationDefendAttackerActivity]
57
+ # @param rule [String]
58
+ def attach_existing existing_attacker_activity, attacker_activity, rule
59
+ # TODO: RUBY-1663 figure out attack time mapping
60
+ new_violation = attacker_activity.protection_rules[rule]
61
+ if (previously_violated = existing_attacker_activity.protection_rules[rule])
62
+ if (new_blocked = new_violation.blocked&.samples)
63
+ unless previously_violated.blocked
64
+ previously_violated.blocked = Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity.new
65
+ end
66
+ previously_violated.blocked.samples.concat(new_blocked)
67
+ end
68
+
69
+ if (new_exploited = new_violation.exploited&.samples)
70
+ unless previously_violated.exploited
71
+ previously_violated.exploited = Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity.new
72
+ end
73
+ previously_violated.exploited.samples.concat(new_exploited)
74
+ end
75
+
76
+ if (new_ineffective = new_violation.ineffective&.samples)
77
+ unless previously_violated.ineffective
78
+ previously_violated.ineffective = Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity.new
79
+ end
80
+ previously_violated.ineffective.samples.concat(new_ineffective)
81
+ end
82
+
83
+ if (new_suspicious = new_violation.suspicious&.samples)
84
+ unless previously_violated.suspicious
85
+ previously_violated.suspicious = Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity.new
86
+ end
87
+ previously_violated.suspicious.samples.concat(new_suspicious)
88
+ end
89
+ else
90
+ existing_attacker_activity.protection_rules[rule] = new_violation
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,70 @@
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/api/dtm.pb'
5
+ require 'contrast/api/decorators/response_type'
6
+ require 'contrast/components/logger'
7
+ require 'contrast/agent/reporting/reporting_events/application_defend_attack_sample_activity'
8
+
9
+ module Contrast
10
+ module Agent
11
+ module Reporting
12
+ # This is the new ApplicationDefendAttackActivity class which will include the attacks sent by the source.
13
+ class ApplicationDefendAttackActivity
14
+ # @return [Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity]
15
+ attr_accessor :blocked
16
+ # @return [Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity]
17
+ attr_accessor :exploited
18
+ # @return [Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity]
19
+ attr_accessor :ineffective
20
+ # @return [Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity]
21
+ attr_accessor :suspicious
22
+
23
+ class << self
24
+ # @param attack_result [Contrast::Api::Dtm::AttackResult]
25
+ def convert attack_result
26
+ activity = new
27
+ activity.attach_data(attack_result)
28
+ activity
29
+ end
30
+ end
31
+
32
+ def initialize
33
+ @start_time = start_time
34
+ super
35
+ end
36
+
37
+ def to_controlled_hash
38
+ {
39
+ startTime: @start_time,
40
+ blocked: blocked&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
41
+ exploited: exploited&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
42
+ ineffective: ineffective&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH,
43
+ suspicious: suspicious&.to_controlled_hash || Contrast::Utils::ObjectShare::EMPTY_HASH
44
+ }
45
+ end
46
+
47
+ # @param attack_result [Contrast::Api::Dtm::AttackResult]
48
+ # @return [Contrast::Agent::Reporting::Defend::AttackSampleActivity]
49
+ def attach_data attack_result
50
+ attack_sample_activity =
51
+ Contrast::Agent::Reporting::ApplicationDefendAttackSampleActivity.convert(attack_result)
52
+ case attack_result.response
53
+ when ::Contrast::Api::Dtm::AttackResult::ResponseType::BLOCKED
54
+ @blocked = attack_sample_activity
55
+ when ::Contrast::Api::Dtm::AttackResult::ResponseType::MONITORED
56
+ @exploited = attack_sample_activity
57
+ when ::Contrast::Api::Dtm::AttackResult::ResponseType::PROBED
58
+ @ineffective = attack_sample_activity
59
+ when ::Contrast::Api::Dtm::AttackResult::ResponseType::SUSPICIOUS
60
+ @suspicious = attack_sample_activity
61
+ end
62
+ end
63
+
64
+ def start_time
65
+ Contrast::Agent::REQUEST_TRACKER.current&.timer&.start_ms
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end