contrast-agent 4.14.0 → 5.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (422) hide show
  1. checksums.yaml +4 -4
  2. data/.simplecov +2 -3
  3. data/Gemfile +1 -1
  4. data/LICENSE.txt +1 -1
  5. data/Rakefile +1 -1
  6. data/exe/contrast_service +1 -1
  7. data/ext/build_funchook.rb +1 -1
  8. data/ext/cs__assess_array/cs__assess_array.c +1 -1
  9. data/ext/cs__assess_array/extconf.rb +1 -1
  10. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +1 -1
  11. data/ext/cs__assess_basic_object/extconf.rb +1 -1
  12. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +1 -1
  13. data/ext/cs__assess_fiber_track/extconf.rb +1 -1
  14. data/ext/cs__assess_hash/cs__assess_hash.c +1 -1
  15. data/ext/cs__assess_hash/extconf.rb +1 -1
  16. data/ext/cs__assess_kernel/cs__assess_kernel.c +8 -5
  17. data/ext/cs__assess_kernel/extconf.rb +1 -1
  18. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +1 -1
  19. data/ext/cs__assess_marshal_module/extconf.rb +1 -1
  20. data/ext/cs__assess_module/cs__assess_module.c +49 -39
  21. data/ext/cs__assess_module/extconf.rb +1 -1
  22. data/ext/cs__assess_regexp/cs__assess_regexp.c +1 -1
  23. data/ext/cs__assess_regexp/extconf.rb +1 -1
  24. data/ext/cs__assess_string/cs__assess_string.c +1 -1
  25. data/ext/cs__assess_string/extconf.rb +1 -1
  26. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +1 -1
  27. data/ext/cs__assess_string_interpolation26/extconf.rb +1 -1
  28. data/ext/cs__assess_yield_track/cs__assess_yield_track.c +1 -1
  29. data/ext/cs__assess_yield_track/extconf.rb +1 -1
  30. data/ext/cs__common/cs__common.c +5 -1
  31. data/ext/cs__common/cs__common.h +1 -0
  32. data/ext/cs__common/extconf.rb +1 -1
  33. data/ext/cs__contrast_patch/cs__contrast_patch.c +53 -28
  34. data/ext/cs__contrast_patch/cs__contrast_patch.h +2 -0
  35. data/ext/cs__contrast_patch/extconf.rb +1 -1
  36. data/ext/cs__os_information/cs__os_information.c +1 -1
  37. data/ext/cs__os_information/extconf.rb +1 -1
  38. data/ext/cs__scope/cs__scope.c +747 -0
  39. data/ext/cs__scope/cs__scope.h +88 -0
  40. data/ext/{cs__assess_active_record_named → cs__scope}/extconf.rb +1 -1
  41. data/ext/extconf_common.rb +1 -1
  42. data/lib/contrast/agent/assess/contrast_event.rb +27 -24
  43. data/lib/contrast/agent/assess/contrast_object.rb +5 -2
  44. data/lib/contrast/agent/assess/events/event_data.rb +30 -0
  45. data/lib/contrast/agent/assess/events/event_factory.rb +14 -6
  46. data/lib/contrast/agent/assess/events/source_event.rb +22 -3
  47. data/lib/contrast/agent/assess/finalizers/freeze.rb +1 -1
  48. data/lib/contrast/agent/assess/finalizers/hash.rb +1 -1
  49. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +7 -7
  50. data/lib/contrast/agent/assess/policy/patcher.rb +1 -35
  51. data/lib/contrast/agent/assess/policy/policy.rb +1 -1
  52. data/lib/contrast/agent/assess/policy/policy_node.rb +2 -2
  53. data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
  54. data/lib/contrast/agent/assess/policy/preshift.rb +1 -1
  55. data/lib/contrast/agent/assess/policy/propagation_method.rb +55 -28
  56. data/lib/contrast/agent/assess/policy/propagation_node.rb +3 -6
  57. data/lib/contrast/agent/assess/policy/propagator/append.rb +1 -1
  58. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  59. data/lib/contrast/agent/assess/policy/propagator/center.rb +1 -1
  60. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  61. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +6 -2
  62. data/lib/contrast/agent/assess/policy/propagator/insert.rb +5 -2
  63. data/lib/contrast/agent/assess/policy/propagator/keep.rb +1 -1
  64. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +13 -3
  65. data/lib/contrast/agent/assess/policy/propagator/next.rb +1 -1
  66. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +1 -1
  67. data/lib/contrast/agent/assess/policy/propagator/rack_protection.rb +1 -1
  68. data/lib/contrast/agent/assess/policy/propagator/remove.rb +1 -1
  69. data/lib/contrast/agent/assess/policy/propagator/replace.rb +1 -1
  70. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +1 -1
  71. data/lib/contrast/agent/assess/policy/propagator/select.rb +3 -2
  72. data/lib/contrast/agent/assess/policy/propagator/splat.rb +1 -1
  73. data/lib/contrast/agent/assess/policy/propagator/split.rb +27 -25
  74. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +3 -5
  75. data/lib/contrast/agent/assess/policy/propagator/substitution_utils.rb +190 -0
  76. data/lib/contrast/agent/assess/policy/propagator/trim.rb +9 -4
  77. data/lib/contrast/agent/assess/policy/propagator.rb +1 -1
  78. data/lib/contrast/agent/assess/policy/source_method.rb +39 -26
  79. data/lib/contrast/agent/assess/policy/source_node.rb +1 -1
  80. data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +1 -1
  81. data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +1 -1
  82. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +7 -2
  83. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +1 -1
  84. data/lib/contrast/agent/assess/policy/trigger_method.rb +41 -25
  85. data/lib/contrast/agent/assess/policy/trigger_node.rb +1 -1
  86. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +1 -1
  87. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +1 -1
  88. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +1 -1
  89. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +1 -1
  90. data/lib/contrast/agent/assess/properties.rb +1 -1
  91. data/lib/contrast/agent/assess/property/evented.rb +25 -12
  92. data/lib/contrast/agent/assess/property/tagged.rb +1 -1
  93. data/lib/contrast/agent/assess/property/updated.rb +1 -1
  94. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +1 -19
  95. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +1 -13
  96. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +7 -59
  97. data/lib/contrast/agent/assess/rule/provider.rb +1 -1
  98. data/lib/contrast/agent/assess/rule/response/auto_complete_rule.rb +69 -0
  99. data/lib/contrast/agent/assess/rule/response/base_rule.rb +130 -0
  100. data/lib/contrast/agent/assess/rule/response/body_rule.rb +109 -0
  101. data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +157 -0
  102. data/lib/contrast/agent/assess/rule/response/click_jacking_header_rule.rb +26 -0
  103. data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +100 -0
  104. data/lib/contrast/agent/assess/rule/response/csp_header_missing_rule.rb +26 -0
  105. data/lib/contrast/agent/assess/rule/response/framework/rails_support.rb +29 -0
  106. data/lib/contrast/agent/assess/rule/response/header_rule.rb +70 -0
  107. data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +36 -0
  108. data/lib/contrast/agent/assess/rule/response/parameters_pollution_rule.rb +61 -0
  109. data/lib/contrast/agent/assess/rule/response/x_content_type_header_rule.rb +26 -0
  110. data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +36 -0
  111. data/lib/contrast/agent/assess/tag.rb +1 -1
  112. data/lib/contrast/agent/assess/tracker.rb +1 -1
  113. data/lib/contrast/agent/assess.rb +1 -2
  114. data/lib/contrast/agent/at_exit_hook.rb +1 -1
  115. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +13 -8
  116. data/lib/contrast/agent/deadzone/policy/policy.rb +1 -1
  117. data/lib/contrast/agent/disable_reaction.rb +1 -1
  118. data/lib/contrast/agent/exclusion_matcher.rb +1 -1
  119. data/lib/contrast/agent/inventory/database_config.rb +115 -77
  120. data/lib/contrast/agent/inventory/dependencies.rb +1 -1
  121. data/lib/contrast/agent/inventory/dependency_analysis.rb +1 -1
  122. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +3 -3
  123. data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
  124. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  125. data/lib/contrast/agent/inventory/policy/trigger_node.rb +1 -1
  126. data/lib/contrast/agent/inventory.rb +1 -1
  127. data/lib/contrast/agent/metric_telemetry_event.rb +1 -1
  128. data/lib/contrast/agent/middleware.rb +4 -2
  129. data/lib/contrast/agent/module_data.rb +1 -1
  130. data/lib/contrast/agent/patching/policy/after_load_patch.rb +1 -1
  131. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +2 -4
  132. data/lib/contrast/agent/patching/policy/method_policy.rb +28 -15
  133. data/lib/contrast/agent/patching/policy/method_policy_extend.rb +12 -10
  134. data/lib/contrast/agent/patching/policy/module_policy.rb +1 -1
  135. data/lib/contrast/agent/patching/policy/patch.rb +3 -7
  136. data/lib/contrast/agent/patching/policy/patch_status.rb +2 -26
  137. data/lib/contrast/agent/patching/policy/patcher.rb +2 -6
  138. data/lib/contrast/agent/patching/policy/policy.rb +1 -1
  139. data/lib/contrast/agent/patching/policy/policy_node.rb +1 -1
  140. data/lib/contrast/agent/patching/policy/trigger_node.rb +1 -1
  141. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +94 -0
  142. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +1 -1
  143. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +1 -1
  144. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +1 -1
  145. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +1 -1
  146. data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +1 -1
  147. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +1 -1
  148. data/lib/contrast/agent/protect/policy/policy.rb +1 -1
  149. data/lib/contrast/agent/protect/policy/rule_applicator.rb +1 -1
  150. data/lib/contrast/agent/protect/policy/trigger_node.rb +1 -1
  151. data/lib/contrast/agent/protect/rule/base.rb +29 -2
  152. data/lib/contrast/agent/protect/rule/base_service.rb +11 -2
  153. data/lib/contrast/agent/protect/rule/cmd_injection.rb +3 -1
  154. data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -1
  155. data/lib/contrast/agent/protect/rule/deserialization.rb +7 -1
  156. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +6 -2
  157. data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +1 -1
  158. data/lib/contrast/agent/protect/rule/no_sqli.rb +2 -1
  159. data/lib/contrast/agent/protect/rule/path_traversal.rb +2 -1
  160. data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +1 -1
  161. data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +1 -1
  162. data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +1 -1
  163. data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +2 -2
  164. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +124 -0
  165. data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +121 -0
  166. data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +1 -1
  167. data/lib/contrast/agent/protect/rule/sqli.rb +34 -1
  168. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +1 -1
  169. data/lib/contrast/agent/protect/rule/xss.rb +1 -1
  170. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +1 -1
  171. data/lib/contrast/agent/protect/rule/xxe.rb +5 -1
  172. data/lib/contrast/agent/protect/rule.rb +1 -1
  173. data/lib/contrast/agent/reaction_processor.rb +1 -1
  174. data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +44 -0
  175. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +115 -0
  176. data/lib/contrast/agent/reporting/input_analysis/input_type.rb +44 -0
  177. data/lib/contrast/agent/reporting/input_analysis/score_level.rb +21 -0
  178. data/lib/contrast/agent/reporting/report.rb +8 -1
  179. data/lib/contrast/agent/reporting/reporter.rb +27 -47
  180. data/lib/contrast/agent/reporting/reporting_events/application_inventory.rb +49 -0
  181. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +82 -0
  182. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +80 -0
  183. data/lib/contrast/agent/reporting/reporting_events/discovered_route.rb +59 -0
  184. data/lib/contrast/agent/reporting/reporting_events/finding.rb +181 -43
  185. data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +293 -0
  186. data/lib/contrast/agent/reporting/reporting_events/finding_event_object.rb +94 -0
  187. data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +39 -0
  188. data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +40 -0
  189. data/lib/contrast/agent/reporting/reporting_events/finding_event_signature.rb +110 -0
  190. data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +61 -0
  191. data/lib/contrast/agent/reporting/reporting_events/finding_event_stack.rb +71 -0
  192. data/lib/contrast/agent/reporting/reporting_events/finding_event_taint_range.rb +60 -0
  193. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +94 -0
  194. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +93 -0
  195. data/lib/contrast/agent/reporting/reporting_events/library_usage_observation.rb +50 -0
  196. data/lib/contrast/agent/reporting/reporting_events/observed_library_usage.rb +54 -0
  197. data/lib/contrast/agent/reporting/reporting_events/observed_route.rb +66 -0
  198. data/lib/contrast/agent/reporting/reporting_events/poll.rb +29 -0
  199. data/lib/contrast/agent/reporting/reporting_events/preflight.rb +20 -6
  200. data/lib/contrast/agent/reporting/reporting_events/preflight_message.rb +36 -17
  201. data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +29 -18
  202. data/lib/contrast/agent/reporting/reporting_events/route_coverage.rb +76 -0
  203. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +67 -0
  204. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +65 -0
  205. data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +52 -0
  206. data/lib/contrast/agent/reporting/reporting_events/trace_event_source.rb +30 -0
  207. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +32 -15
  208. data/lib/contrast/agent/reporting/reporting_utilities/dtm_message.rb +67 -0
  209. data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +164 -0
  210. data/lib/contrast/agent/reporting/reporting_utilities/headers.rb +55 -0
  211. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +75 -156
  212. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +162 -0
  213. data/lib/contrast/agent/reporting/reporting_utilities/reporting_storage.rb +1 -1
  214. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +30 -0
  215. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +57 -0
  216. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +208 -0
  217. data/lib/contrast/agent/reporting/settings/application_settings.rb +67 -0
  218. data/lib/contrast/agent/reporting/settings/assess.rb +45 -0
  219. data/lib/contrast/agent/reporting/settings/assess_server_feature.rb +136 -0
  220. data/lib/contrast/agent/reporting/settings/exclusions.rb +123 -0
  221. data/lib/contrast/agent/reporting/settings/protect.rb +89 -0
  222. data/lib/contrast/agent/reporting/settings/protect_server_feature.rb +243 -0
  223. data/lib/contrast/agent/reporting/settings/reaction.rb +30 -0
  224. data/lib/contrast/agent/reporting/settings/server_features.rb +78 -0
  225. data/lib/contrast/agent/request.rb +44 -3
  226. data/lib/contrast/agent/request_context.rb +25 -7
  227. data/lib/contrast/agent/request_context_extend.rb +109 -7
  228. data/lib/contrast/agent/request_handler.rb +41 -5
  229. data/lib/contrast/agent/response.rb +23 -15
  230. data/lib/contrast/agent/rule_set.rb +1 -1
  231. data/lib/contrast/agent/scope.rb +103 -108
  232. data/lib/contrast/agent/service_heartbeat.rb +46 -3
  233. data/lib/contrast/agent/startup_metrics_telemetry_event.rb +34 -7
  234. data/lib/contrast/agent/static_analysis.rb +13 -3
  235. data/lib/contrast/agent/telemetry.rb +1 -1
  236. data/lib/contrast/agent/telemetry_event.rb +1 -1
  237. data/lib/contrast/agent/thread.rb +1 -1
  238. data/lib/contrast/agent/thread_watcher.rb +3 -3
  239. data/lib/contrast/agent/tracepoint_hook.rb +1 -4
  240. data/lib/contrast/agent/version.rb +2 -2
  241. data/lib/contrast/agent/worker_thread.rb +1 -1
  242. data/lib/contrast/agent.rb +4 -4
  243. data/lib/contrast/api/communication/connection_status.rb +1 -1
  244. data/lib/contrast/api/communication/messaging_queue.rb +4 -4
  245. data/lib/contrast/api/communication/response_processor.rb +9 -5
  246. data/lib/contrast/api/communication/service_lifecycle.rb +1 -1
  247. data/lib/contrast/api/communication/socket.rb +1 -1
  248. data/lib/contrast/api/communication/socket_client.rb +4 -1
  249. data/lib/contrast/api/communication/speedracer.rb +1 -1
  250. data/lib/contrast/api/communication/tcp_socket.rb +1 -1
  251. data/lib/contrast/api/communication/unix_socket.rb +1 -1
  252. data/lib/contrast/api/communication.rb +1 -1
  253. data/lib/contrast/api/decorators/address.rb +1 -1
  254. data/lib/contrast/api/decorators/agent_startup.rb +1 -1
  255. data/lib/contrast/api/decorators/application_settings.rb +1 -1
  256. data/lib/contrast/api/decorators/application_startup.rb +1 -1
  257. data/lib/contrast/api/decorators/application_update.rb +1 -1
  258. data/lib/contrast/api/decorators/architecture_component.rb +36 -0
  259. data/lib/contrast/api/decorators/bot_blocker.rb +37 -0
  260. data/lib/contrast/api/decorators/finding.rb +1 -17
  261. data/lib/contrast/api/decorators/http_request.rb +3 -2
  262. data/lib/contrast/api/decorators/input_analysis.rb +1 -1
  263. data/lib/contrast/api/decorators/instrumentation_mode.rb +1 -1
  264. data/lib/contrast/api/decorators/ip_denylist.rb +37 -0
  265. data/lib/contrast/api/decorators/library.rb +1 -1
  266. data/lib/contrast/api/decorators/library_usage_update.rb +1 -1
  267. data/lib/contrast/api/decorators/message.rb +1 -1
  268. data/lib/contrast/api/decorators/rasp_rule_sample.rb +30 -1
  269. data/lib/contrast/api/decorators/route_coverage.rb +1 -1
  270. data/lib/contrast/api/decorators/server_features.rb +1 -1
  271. data/lib/contrast/api/decorators/trace_event.rb +1 -1
  272. data/lib/contrast/api/decorators/trace_event_object.rb +1 -1
  273. data/lib/contrast/api/decorators/trace_event_signature.rb +1 -1
  274. data/lib/contrast/api/decorators/trace_taint_range.rb +1 -1
  275. data/lib/contrast/api/decorators/trace_taint_range_tags.rb +1 -1
  276. data/lib/contrast/api/decorators/user_input.rb +12 -2
  277. data/lib/contrast/api/decorators/virtual_patch.rb +34 -0
  278. data/lib/contrast/api/decorators.rb +2 -1
  279. data/lib/contrast/api.rb +1 -1
  280. data/lib/contrast/components/agent.rb +5 -24
  281. data/lib/contrast/components/api.rb +18 -9
  282. data/lib/contrast/components/app_context.rb +2 -1
  283. data/lib/contrast/components/app_context_extend.rb +1 -1
  284. data/lib/contrast/components/assess.rb +12 -8
  285. data/lib/contrast/components/base.rb +1 -1
  286. data/lib/contrast/components/config.rb +30 -15
  287. data/lib/contrast/components/contrast_service.rb +1 -1
  288. data/lib/contrast/components/heap_dump.rb +1 -1
  289. data/lib/contrast/components/inventory.rb +5 -1
  290. data/lib/contrast/components/logger.rb +6 -1
  291. data/lib/contrast/components/protect.rb +10 -4
  292. data/lib/contrast/components/sampling.rb +1 -1
  293. data/lib/contrast/components/scope.rb +99 -92
  294. data/lib/contrast/components/settings.rb +25 -12
  295. data/lib/contrast/config/agent_configuration.rb +59 -13
  296. data/lib/contrast/config/api_configuration.rb +101 -13
  297. data/lib/contrast/config/api_proxy_configuration.rb +56 -4
  298. data/lib/contrast/config/application_configuration.rb +115 -16
  299. data/lib/contrast/config/assess_configuration.rb +107 -13
  300. data/lib/contrast/config/assess_rules_configuration.rb +45 -4
  301. data/lib/contrast/config/base_configuration.rb +2 -1
  302. data/lib/contrast/config/certification_configuration.rb +75 -4
  303. data/lib/contrast/config/env_variables.rb +1 -1
  304. data/lib/contrast/config/exception_configuration.rb +62 -4
  305. data/lib/contrast/config/heap_dump_configuration.rb +102 -18
  306. data/lib/contrast/config/inventory_configuration.rb +65 -4
  307. data/lib/contrast/config/logger_configuration.rb +47 -4
  308. data/lib/contrast/config/protect_configuration.rb +1 -1
  309. data/lib/contrast/config/protect_rule_configuration.rb +37 -10
  310. data/lib/contrast/config/protect_rules_configuration.rb +121 -18
  311. data/lib/contrast/config/request_audit_configuration.rb +69 -4
  312. data/lib/contrast/config/root_configuration.rb +1 -1
  313. data/lib/contrast/config/ruby_configuration.rb +97 -20
  314. data/lib/contrast/config/sampling_configuration.rb +77 -11
  315. data/lib/contrast/config/server_configuration.rb +57 -12
  316. data/lib/contrast/config/service_configuration.rb +1 -1
  317. data/lib/contrast/config.rb +1 -1
  318. data/lib/contrast/configuration.rb +7 -4
  319. data/lib/contrast/extension/assess/array.rb +4 -2
  320. data/lib/contrast/extension/assess/erb.rb +32 -5
  321. data/lib/contrast/extension/assess/eval_trigger.rb +3 -1
  322. data/lib/contrast/extension/assess/exec_trigger.rb +2 -1
  323. data/lib/contrast/extension/assess/fiber.rb +6 -3
  324. data/lib/contrast/extension/assess/hash.rb +1 -1
  325. data/lib/contrast/extension/assess/kernel.rb +8 -3
  326. data/lib/contrast/extension/assess/marshal.rb +6 -2
  327. data/lib/contrast/extension/assess/regexp.rb +8 -2
  328. data/lib/contrast/extension/assess/string.rb +8 -2
  329. data/lib/contrast/extension/assess.rb +1 -1
  330. data/lib/contrast/extension/delegator.rb +1 -1
  331. data/lib/contrast/extension/extension.rb +2 -4
  332. data/lib/contrast/extension/inventory.rb +1 -1
  333. data/lib/contrast/extension/module.rb +1 -1
  334. data/lib/contrast/extension/protect/psych.rb +1 -1
  335. data/lib/contrast/extension/protect.rb +1 -1
  336. data/lib/contrast/extension/thread.rb +32 -13
  337. data/lib/contrast/framework/base_support.rb +5 -1
  338. data/lib/contrast/framework/grape/support.rb +25 -1
  339. data/lib/contrast/framework/manager.rb +26 -5
  340. data/lib/contrast/framework/manager_extend.rb +1 -1
  341. data/lib/contrast/framework/platform_version.rb +1 -1
  342. data/lib/contrast/framework/rack/patch/session_cookie.rb +1 -1
  343. data/lib/contrast/framework/rack/patch/support.rb +1 -1
  344. data/lib/contrast/framework/rack/support.rb +1 -1
  345. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -1
  346. data/lib/contrast/framework/rails/patch/assess_configuration.rb +1 -1
  347. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +1 -1
  348. data/lib/contrast/framework/rails/patch/support.rb +1 -1
  349. data/lib/contrast/framework/rails/railtie.rb +1 -1
  350. data/lib/contrast/framework/rails/support.rb +46 -2
  351. data/lib/contrast/framework/sinatra/support.rb +24 -2
  352. data/lib/contrast/funchook/funchook.rb +21 -18
  353. data/lib/contrast/logger/application.rb +1 -1
  354. data/lib/contrast/logger/cef_log.rb +151 -0
  355. data/lib/contrast/logger/format.rb +1 -1
  356. data/lib/contrast/logger/log.rb +1 -1
  357. data/lib/contrast/logger/request.rb +1 -1
  358. data/lib/contrast/logger/time.rb +1 -1
  359. data/lib/contrast/security_exception.rb +1 -1
  360. data/lib/contrast/tasks/config.rb +1 -1
  361. data/lib/contrast/tasks/service.rb +1 -1
  362. data/lib/contrast/utils/assess/propagation_method_utils.rb +1 -1
  363. data/lib/contrast/utils/assess/property/tagged_utils.rb +1 -1
  364. data/lib/contrast/utils/assess/sampling_util.rb +4 -4
  365. data/lib/contrast/utils/assess/source_method_utils.rb +1 -1
  366. data/lib/contrast/utils/assess/split_utils.rb +23 -0
  367. data/lib/contrast/utils/assess/tracking_util.rb +1 -1
  368. data/lib/contrast/utils/assess/trigger_method_utils.rb +3 -2
  369. data/lib/contrast/utils/class_util.rb +1 -1
  370. data/lib/contrast/utils/duck_utils.rb +1 -1
  371. data/lib/contrast/utils/env_configuration_item.rb +2 -2
  372. data/lib/contrast/utils/exclude_key.rb +1 -1
  373. data/lib/contrast/utils/findings.rb +5 -2
  374. data/lib/contrast/utils/hash_digest.rb +44 -6
  375. data/lib/contrast/utils/hash_digest_extend.rb +44 -1
  376. data/lib/contrast/utils/head_dump_utils_extend.rb +1 -1
  377. data/lib/contrast/utils/heap_dump_util.rb +1 -1
  378. data/lib/contrast/utils/invalid_configuration_util.rb +6 -5
  379. data/lib/contrast/utils/io_util.rb +1 -1
  380. data/lib/contrast/utils/job_servers_running.rb +1 -1
  381. data/lib/contrast/utils/log_utils.rb +115 -1
  382. data/lib/contrast/utils/lru_cache.rb +1 -1
  383. data/lib/contrast/utils/metrics_hash.rb +2 -2
  384. data/lib/contrast/utils/middleware_utils.rb +7 -8
  385. data/lib/contrast/utils/net_http_base.rb +26 -16
  386. data/lib/contrast/utils/object_share.rb +1 -6
  387. data/lib/contrast/utils/os.rb +9 -5
  388. data/lib/contrast/utils/patching/policy/patch_utils.rb +62 -102
  389. data/lib/contrast/utils/patching/policy/patcher_utils.rb +1 -1
  390. data/lib/contrast/utils/preflight_util.rb +1 -1
  391. data/lib/contrast/utils/request_utils.rb +9 -1
  392. data/lib/contrast/utils/resource_loader.rb +1 -1
  393. data/lib/contrast/utils/response_utils.rb +1 -1
  394. data/lib/contrast/utils/sha256_builder.rb +1 -1
  395. data/lib/contrast/utils/stack_trace_utils.rb +1 -1
  396. data/lib/contrast/utils/string_utils.rb +69 -67
  397. data/lib/contrast/utils/tag_util.rb +2 -1
  398. data/lib/contrast/utils/telemetry.rb +1 -1
  399. data/lib/contrast/utils/telemetry_client.rb +1 -1
  400. data/lib/contrast/utils/telemetry_identifier.rb +1 -1
  401. data/lib/contrast/utils/thread_tracker.rb +1 -1
  402. data/lib/contrast/utils/timer.rb +1 -1
  403. data/lib/contrast-agent.rb +1 -1
  404. data/lib/contrast.rb +5 -4
  405. data/resources/assess/policy.json +10 -0
  406. data/ruby-agent.gemspec +4 -5
  407. data/service_executables/VERSION +1 -1
  408. data/service_executables/linux/contrast-service +0 -0
  409. data/service_executables/mac/contrast-service +0 -0
  410. metadata +96 -40
  411. data/ext/cs__assess_active_record_named/cs__active_record_named.c +0 -46
  412. data/ext/cs__assess_active_record_named/cs__active_record_named.h +0 -11
  413. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +0 -95
  414. data/lib/contrast/agent/class_reopener.rb +0 -258
  415. data/lib/contrast/agent/rewriter.rb +0 -259
  416. data/lib/contrast/extension/kernel.rb +0 -54
  417. data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +0 -37
  418. data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +0 -41
  419. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +0 -75
  420. data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +0 -35
  421. data/lib/contrast/utils/ruby_ast_rewriter.rb +0 -82
  422. data/lib/contrast/utils/substitution_utils.rb +0 -167
@@ -1,68 +1,172 @@
1
- # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
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
4
  require 'json'
5
5
  require 'contrast/components/logger'
6
+ require 'contrast/agent/reporting/reporting_events/finding_event'
7
+ require 'contrast/agent/reporting/reporting_events/finding_request'
6
8
  require 'contrast/agent/reporting/reporting_events/reporting_event'
9
+ require 'contrast/agent/assess/events/event_data'
10
+ require 'contrast/utils/timer'
7
11
 
8
12
  module Contrast
9
13
  module Agent
10
14
  module Reporting
11
- # This is the new Findings class which will include all the needed information
12
- # for the new reporting system
15
+ # This is the new Finding class which will include all the needed information for the new reporting system to
16
+ # relay this information in the Finding/Trace messages. These findings are used by TeamServer to construct the
17
+ # vulnerability information for the assess feature. They represent those parts of the application, either through
18
+ # configuration, method invocation, or dataflow, which are determined to be insecure.
13
19
  class Finding < Contrast::Agent::Reporting::ReportingEvent
14
- attr_accessor :events, :properties, :request, :hash_code
20
+ include Contrast::Components::Logger::InstanceMethods
21
+
22
+ # @return [Integer] the time, in ms, that this object was initialized
23
+ attr_reader :created
24
+ # @return [String] the ID of the rule associated with this finding
15
25
  attr_reader :rule_id
26
+ # @return [Array<Contrast::Agent::Reporting::RouteDiscovery>] the routes associated with this finding, if the
27
+ # finding is request based.
28
+ attr_reader :routes
29
+ # @return [Array<Contrast::Agent::Reporting::FindingEvent>] the events associated with this finding, if the
30
+ # finding is event (dataflow) based.
31
+ attr_reader :events
32
+ # @return [String] the evidence associated with this finding, if the finding is event based. deprecated in
33
+ # favor of properties
34
+ # attr_reader :evidence
35
+ # @return [Hash<String,String>] properties that prove the violation of the rule for this finding
36
+ attr_reader :properties
37
+ # @return [Contrast::Agent::Reporting::FindingRequest] the request associated with this finding, if the finding
38
+ # is request based
39
+ attr_reader :request
40
+ # @return [String] the uniquely identifying hash of this finding
41
+ attr_accessor :hash_code
42
+
43
+ CONFIGURATION_RULES = %w[rails-http-only-disabled secure-flag-missing session-timeout].cs__freeze
44
+ HARDCODED_RULES = %w[hardcoded-key hardcoded-password].cs__freeze
45
+ PROPERTIES_RULES = %w[
46
+ autocomplete-missing
47
+ cache-controls-missing
48
+ clickjacking-control-missing
49
+ csp-header-missing
50
+ csp-header-insecure
51
+ hsts-header-missing
52
+ parameter-pollution
53
+ xcontenttype-header-missing
54
+ xxssprotection-header-disabled
55
+ ].cs__freeze
56
+
57
+ class << self
58
+ # @param finding_dtm [Contrast::Api::Dtm::Finding]
59
+ # @return [Contrast::Agent::Reporting::Finding]
60
+ def convert finding_dtm
61
+ report = new(finding_dtm.rule_id)
62
+ report.attach_property_data(finding_dtm)
63
+ report
64
+ end
65
+ end
16
66
 
17
67
  def initialize rule_id
18
- super
19
- @event_type = :report_vulnerability
68
+ @event_method = :PUT
69
+ @event_endpoint = "#{ Contrast::API.api_url }/api/ng/traces"
20
70
  @events = []
21
- @platform = Contrast::Utils::ObjectShare::RUBY
71
+ @routes = []
22
72
  @rule_id = Contrast::Utils::StringUtils.truncate(rule_id)
23
73
  @properties = {}
74
+ @created = Contrast::Utils::Timer.now_ms
75
+ super()
76
+ end
77
+
78
+ # Some reports require specific additional headers to be used. To that end, we'll attach them here, letting
79
+ # each handle their own.
80
+ #
81
+ # @param request [Net::HTTPRequest]
82
+ def attach_headers request
83
+ request['Report-Hash'] = hash_code
24
84
  end
25
85
 
86
+ # @param trigger_node [Contrast::Agent::Assess::Policy::TriggerNode] the node to direct applying this
87
+ # trigger event
88
+ # @param source [Object] the source of the Trigger Event
89
+ # @param object [Object] the Object on which the method was invoked
90
+ # @param ret [Object] the Return of the invoked method
91
+ # @param request [Contrast::Agent::Request]
92
+ # @param args [Array<Object>] the Arguments with which the method was invoked
26
93
  def attach_data trigger_node, source, object, ret, request, *args
27
- @events << Contrast::Agent::Assess::Events::EventFactory.build(trigger_node, source, object, ret, args)
28
- @request = request
29
- from_properties source, @events
30
- attach_routes request
94
+ event_messages = Contrast::Agent::Reporting::FindingEvent.from_source(source)
95
+ events.concat(event_messages) if event_messages&.any?
96
+ event_data = Contrast::Agent::Assess::Events::EventData.new(trigger_node, source, object, ret, args)
97
+ contrast_event = Contrast::Agent::Assess::ContrastEvent.new(event_data)
98
+ events << Contrast::Agent::Reporting::FindingEvent.convert(contrast_event)
99
+ attach_properties
100
+ return unless request
101
+
102
+ @request = Contrast::Agent::Reporting::FindingRequest.convert(request)
103
+ @routes << Contrast::Agent::Reporting::RouteDiscovery.convert(request.route)
31
104
  end
32
105
 
33
- def to_controlled_hash **_args
106
+ # Attach the data from a Contrast::Api::Dtm::Finding required for property based findings generated during
107
+ # response analysis.
108
+ #
109
+ # @param finding_dtm [Contrast::Api::Dtm::Finding]
110
+ def attach_property_data finding_dtm
111
+ @hash_code = finding_dtm.hash_code
112
+ @rule_id = finding_dtm.rule_id
113
+ finding_dtm.properties.each_pair do |key, value|
114
+ @properties[key] = value
115
+ end
116
+ finding_dtm.routes.each do |route|
117
+ @routes << Contrast::Agent::Reporting::RouteDiscovery.convert(route)
118
+ end
119
+ request = Contrast::Agent::REQUEST_TRACKER.current&.request
120
+ @request = Contrast::Agent::Reporting::FindingRequest.convert(request) if request
121
+ end
122
+
123
+ # Convert the instance variables on the class, and other information, into the identifiers required for
124
+ # TeamServer to process the JSON form of this message.
125
+ #
126
+ # @return [Hash]
127
+ # @raise [ArgumentError]
128
+ def to_controlled_hash
34
129
  validate
35
- {
36
- platform: @platform,
37
- ruleId: @rule_id,
38
- request: request,
39
- properties: properties,
40
- events: events,
41
- routes: routes
130
+ hsh = {
131
+ created: created,
132
+ hash: hash_code.to_s,
133
+ ruleId: rule_id,
134
+ session_id: @agent_session_id_value.to_s,
135
+ version: 4
42
136
  }
137
+ hsh[:events] = events.map(&:to_controlled_hash) if event_based?
138
+ # hsh[:evidence] = evidence unless event_based? || property_based?
139
+ hsh[:properties] = properties if property_based?
140
+ hsh[:tags] = Contrast::ASSESS.tags if Contrast::ASSESS.tags
141
+ return hsh unless request_based?
142
+
143
+ hsh[:request] = request.to_controlled_hash
144
+ hsh[:routes] = routes.map(&:to_controlled_hash)
145
+ hsh
43
146
  end
44
147
 
148
+ # @raise [ArgumentError]
45
149
  def validate
46
- raise(ArgumentError, "#{ self } did not have a proper platform. Unable to continue.") unless @platform
47
150
  raise(ArgumentError, "#{ self } did not have a proper rule. Unable to continue.") unless @rule_id
48
- raise(ArgumentError, "#{ self } did not have proper events. Unable to continue.") if events.empty?
49
- raise(ArgumentError, "#{ self } did not have proper properties. Unable to continue.") if properties.empty?
50
- raise(ArgumentError, "#{ self } did not have a proper request. Unable to continue.") unless request
51
151
 
52
- nil
152
+ if event_based? && events.empty?
153
+ raise(ArgumentError, "#{ self } did not have proper events for #{ @rule_id }. Unable to continue.")
154
+ end
155
+ if property_based? && properties.empty?
156
+ raise(ArgumentError, "#{ self } did not have proper properties for #{ @rule_id }. Unable to continue.")
157
+ end
158
+ return unless request_based? && request.nil?
159
+
160
+ raise(ArgumentError, "#{ self } did not have a proper request for #{ @rule_id }. Unable to continue.")
53
161
  end
54
162
 
55
163
  private
56
164
 
57
- def from_properties source, events
58
- return unless source
59
- return unless Contrast::Agent::Assess::Tracker.trackable?(source)
60
-
61
- properties = Contrast::Agent::Assess::Tracker.properties(source)
62
-
63
- build_events events, properties.event if properties.event
64
- @properties = properties if properties
65
- end
165
+ # Our events have properties on them. To report them to TeamServer, we need to pull them from our object up to
166
+ # the Contrast::Agent::Reporting::Finding level.
167
+ #
168
+ # TODO: RUBY-99999 put properties on events, not just on DTM
169
+ def attach_properties; end
66
170
 
67
171
  def build_events events, event
68
172
  return unless event
@@ -70,19 +174,53 @@ module Contrast
70
174
  event.parent_events&.each do |parent_event|
71
175
  build_events(events, parent_event)
72
176
  end
73
-
74
177
  events << event
75
178
  end
76
179
 
77
- def attach_routes request
78
- context = Contrast::Agent::REQUEST_TRACKER.current
79
- if context
80
- @routes << context.route if context.route
81
- elsif request&.route
82
- @routes << request.route
83
- elsif request&.path
84
- @routes << request.path
85
- end
180
+ # Rules which are event based must have an event to be sent to TeamServer. They include the Trigger, Regexp,
181
+ # and Data flow type Rules, meaning all those which are not Properties based. Eventually, we may have
182
+ # validation for each of those types; however, that's a refactor for after we've translated all rules from the
183
+ # Service and have had time to build proper child structure.
184
+ #
185
+ # @return [Boolean]
186
+ def event_based?
187
+ !property_based? && !config_based?
188
+ end
189
+
190
+ # Rules which are property based must have a property to be sent to TeamServer. Eventually, each rule may own
191
+ # its own validation, as the properties each needs are different; however, that's a refactor for after we've
192
+ # translated all rules from the Service and have had time to build proper child structure.
193
+ #
194
+ # @return [Boolean]
195
+ def property_based?
196
+ PROPERTIES_RULES.include?(@rule_id)
197
+ end
198
+
199
+ # Rules which are config based must have a configuration to be sent to TeamServer. Eventually, each rule may own
200
+ # its own validation, as the properties each needs are different; however, that's a refactor for after we've
201
+ # translated all rules from the Service and have had time to build proper child structure.
202
+ #
203
+ # @return [Boolean]
204
+ def config_based?
205
+ CONFIGURATION_RULES.include?(@rule_id)
206
+ end
207
+
208
+ # Rules which are hardcode based send properties to TeamServer. Eventually, each rule may own its own
209
+ # validation, as the properties each needs are different; however, that's a refactor for after we've
210
+ # translated all rules from the Service and have had time to build proper child structure.
211
+ #
212
+ # @return [Boolean]
213
+ def hardcoded?
214
+ HARDCODED_RULES.include?(@rule_id)
215
+ end
216
+
217
+ # Rules which are request based must have a request to be sent to TeamServer. Most rules fit this category, so
218
+ # we'll default to true for now. Eventually, this will be split out for those rules, like Hardcoded, which do
219
+ # not need requests.
220
+ #
221
+ # @return [Boolean]
222
+ def request_based?
223
+ !config_based? && !hardcoded?
86
224
  end
87
225
  end
88
226
  end
@@ -0,0 +1,293 @@
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/finding_event_object'
5
+ require 'contrast/agent/reporting/reporting_events/finding_event_parent_object'
6
+ require 'contrast/agent/reporting/reporting_events/finding_event_property'
7
+ require 'contrast/agent/reporting/reporting_events/finding_event_signature'
8
+ require 'contrast/agent/reporting/reporting_events/finding_event_source'
9
+ require 'contrast/agent/reporting/reporting_events/finding_event_stack'
10
+ require 'contrast/agent/reporting/reporting_events/finding_event_taint_range'
11
+
12
+ module Contrast
13
+ module Agent
14
+ module Reporting
15
+ # This is the new FindingEvent class which will include all the needed information for the new reporting system
16
+ # to relay this information in the Finding/Trace messages. These FindingEvents are used by TeamServer to
17
+ # construct the vulnerability information for the assess feature. They represent the operation the application
18
+ # underwent that transformed data during the dataflow.
19
+ class FindingEvent
20
+ # @return [Symbol] what the event did; CREATION, A2O, A2P, A2A, A2R, O2A, O2O, O2P, O2R, P2A, P2O, P2P, P2R,
21
+ # TAG, TRIGGER.
22
+ attr_reader :action
23
+ # @return [Array<Contrast::Agent::Reporting::FindingEventObject>] the arguments passed to the method.
24
+ attr_reader :args
25
+ # @return [nil] unused.
26
+ attr_reader :code
27
+ # @return [Integer] the id of this event.
28
+ attr_reader :event_id
29
+ # @return [Array<Contrast::Agent::Reporting::FindingEventSource>] the source of taint
30
+ attr_reader :event_sources
31
+ # @return [nil] unused.
32
+ attr_reader :field_name
33
+ # @return [Contrast::Agent::Reporting::FindingEventObject] the object this method was invoked on.
34
+ attr_reader :object
35
+ # @@return [Array<Contrast::Agent::Reporting::FindingEventParentObject>] the ids of all the events directly
36
+ # preceding this
37
+ attr_reader :parent_object_ids
38
+ # @return [Array<Contrast::Agent::Reporting::FindingEventProperty>]
39
+ attr_reader :properties
40
+ # @return [Contrast::Agent::Reporting::FindingEventObject] the return of the method.
41
+ attr_reader :ret
42
+ # @return [Contrast::Agent::Reporting::FindingEventSignature] the signature of the method.
43
+ attr_reader :signature
44
+ # @return [String] the source of the taint from the method; ^(O|R|P\d+)$
45
+ attr_reader :source
46
+ # @return [Array<Contrast::Agent::Reporting::FindingEventStack>]
47
+ attr_reader :stack
48
+ # @return [String] comma separated list of descriptions of what's happened to the data
49
+ attr_reader :tags
50
+ # @return [Array<Contrast::Agent::Reporting::FindingEventTaintRange>] the tags and spans of the source that are
51
+ # tracked
52
+ attr_reader :taint_ranges
53
+ # @return [String] the target of the taint from the method; ^(O|R|P\d+)$
54
+ attr_reader :target
55
+ # @return [String] the id of the thread on which the method was invoked
56
+ attr_reader :thread
57
+ # @return [Integer] the time, in ms, when the event was generated
58
+ attr_reader :time
59
+ # @return [String] the type of event; METHOD, PROPAGATION, TAG
60
+ attr_reader :type
61
+
62
+ class << self
63
+ # Find all the events leading up to the given source and return an array of FindingEvents
64
+ #
65
+ # @param source [Object] something that may have been tracked
66
+ # @return [Array<Contrast::Agent::Reporting::FindingEvent>]
67
+ def from_source source
68
+ return unless source && (props = Contrast::Agent::Assess::Tracker.properties(source))
69
+
70
+ build_events([], props.event) if props.event
71
+ end
72
+
73
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
74
+ # @return [Contrast::Agent::Reporting::FindingEvent]
75
+ def convert event
76
+ report = new
77
+ report.attach_data(event)
78
+ report
79
+ end
80
+
81
+ private
82
+
83
+ # Pull the parent events from the given event, generating an array of FindingEvents, passing back the given
84
+ # array of events after populating it.
85
+ #
86
+ # @param events [Array<Contrast::Agent::Reporting::FindingEvent>]
87
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
88
+ # @return [Array<Contrast::Agent::Reporting::FindingEvent>]
89
+ def build_events events, event
90
+ return unless event
91
+
92
+ event.parent_events&.each do |parent_event|
93
+ build_events(events, parent_event)
94
+ end
95
+ events << convert(event)
96
+ events
97
+ end
98
+ end
99
+
100
+ # Parse the data from a Contrast::Agent::Assess::ContrastEvent to attach what is required for reporting to
101
+ # TeamServer to this Contrast::Agent::Reporting::FindingEvent
102
+ #
103
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
104
+ def attach_data event
105
+ @event_id = event.event_id
106
+ @time = event.time.to_i
107
+ @thread = event.thread.to_s
108
+ display_params!(event)
109
+ dataflow!(event)
110
+ event_sources!(event)
111
+ @signature = Contrast::Agent::Reporting::FindingEventSignature.convert(event)
112
+ stack!(event)
113
+ parent_ids!(event)
114
+ properties!(event)
115
+ end
116
+
117
+ # Convert the instance variables on the class, and other information, into the identifiers required for
118
+ # TeamServer to process the JSON form of this message.
119
+ #
120
+ # @return [Hash]
121
+ # @raise [ArgumentError]
122
+ def to_controlled_hash # rubocop:disable Metrics/AbcSize
123
+ validate
124
+ {
125
+ action: action,
126
+ args: args.map(&:to_controlled_hash),
127
+ # code: code, # Unused by our agent
128
+ objectId: event_id,
129
+ eventSources: event_sources.map(&:to_controlled_hash),
130
+ # fieldName: field_name, # Unused by our agent
131
+ object: object.to_controlled_hash,
132
+ parentObjectIds: parent_object_ids.map(&:to_controlled_hash),
133
+ properties: properties.map(&:to_controlled_hash),
134
+ ret: ret&.to_controlled_hash,
135
+ signature: signature.to_controlled_hash,
136
+ source: source || '',
137
+ stack: stack.map(&:to_controlled_hash),
138
+ tags: tags.join(','),
139
+ taintRanges: taint_ranges.map(&:to_controlled_hash),
140
+ target: target || '',
141
+ thread: thread,
142
+ time: time,
143
+ type: type
144
+ }
145
+ end
146
+
147
+ # @raise [ArgumentError]
148
+ def validate
149
+ validate_base
150
+ validate_dataflow
151
+ end
152
+
153
+ private
154
+
155
+ # Find the action and type of this event, used by TeamServer to display type of the event and the
156
+ # transformation if made.
157
+ #
158
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
159
+ def display_params! event
160
+ @action = event.policy_node.build_action
161
+ @type = case event.policy_node.node_type
162
+ when :TYPE_TAG
163
+ 'TAG'
164
+ when :TYPE_PROPAGATION
165
+ 'PROPAGATION'
166
+ else # :TYPE_METHOD
167
+ 'METHOD'
168
+ end
169
+ end
170
+
171
+ # Build the dataflow components of this FindingEvent.
172
+ #
173
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
174
+ def dataflow! event
175
+ taint_target = taint_target!(event)
176
+ truncate_obj = Contrast::Utils::ObjectShare::OBJECT_KEY != taint_target
177
+ @object = Contrast::Agent::Reporting::FindingEventObject.convert(event.object, truncate_obj)
178
+ truncate_ret = Contrast::Utils::ObjectShare::RETURN_KEY != taint_target
179
+ @ret = Contrast::Agent::Reporting::FindingEventObject.convert(event.ret, truncate_ret)
180
+ event_args!(event, taint_target)
181
+ taint_ranges!(event)
182
+ end
183
+
184
+ # Convert the arguments of the given ContrastEvent to the reportable form for this FindingEvent. We'll
185
+ # truncate any argument that isn't the taint target of this event.
186
+ #
187
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
188
+ # @param taint_target [String,nil] the target of the taint in this event.
189
+ def event_args! event, taint_target
190
+ @args = []
191
+ idx = 0
192
+ while idx < event.args.length
193
+ @args << Contrast::Agent::Reporting::FindingEventObject.convert(event.args[idx], taint_target != idx)
194
+ idx += 1
195
+ end
196
+ end
197
+
198
+ # Convert the sources of the event to sources here
199
+ #
200
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
201
+ def event_sources! event
202
+ @event_sources = []
203
+ return unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
204
+
205
+ source = Contrast::Agent::Reporting::FindingEventSource.convert(event)
206
+ event_sources << source if source
207
+ end
208
+
209
+ # Convert the parent id's of the given ContrastEvent to the reportable form for this FindingEvent.
210
+ #
211
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
212
+ def parent_ids! event
213
+ @parent_object_ids = []
214
+ event.parent_events&.each do |parent_event|
215
+ parent_object_ids << Contrast::Agent::Reporting::FindingEventParentObject.new(parent_event.event_id.to_i)
216
+ end
217
+ end
218
+
219
+ # Convert the properties of the given ContrastEvent to the reportable form for this FindingEvent.
220
+ # TODO: RUBY-99999 How do properties get to events? Do they? I thought Stored-XSS needed it.
221
+ #
222
+ # @param _event [Contrast::Agent::Assess::ContrastEvent]
223
+ def properties! _event
224
+ @properties = []
225
+ end
226
+
227
+ # Convert the stack of the given ContrastEvent to the reportable form for this FindingEvent.
228
+ #
229
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
230
+ def stack! event
231
+ @stack = []
232
+ event.stack_trace.each do |stack_event|
233
+ if (report = Contrast::Agent::Reporting::FindingEventStack.convert(stack_event))
234
+ stack << report
235
+ end
236
+ end
237
+ end
238
+
239
+ # Convert the taint ranges of the given ContrastEvent to the reportable form for this FindingEvent.
240
+ #
241
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
242
+ def taint_ranges! event
243
+ @tags = []
244
+ @taint_ranges = []
245
+ event&.tags&.each_pair do |tag_key, tag_ranges|
246
+ tags << tag_key
247
+ tag_ranges.each do |range|
248
+ taint_ranges << Contrast::Agent::Reporting::FindingEventTaintRange.convert(range)
249
+ end
250
+ end
251
+ end
252
+
253
+ # Find the source and target for this FindingEvent based on the provided event.
254
+ #
255
+ # @param event [Contrast::Agent::Assess::ContrastEvent]
256
+ # @return [String,nil] the target of the taint in this event.
257
+ def taint_target! event
258
+ return unless (node = event.policy_node)
259
+
260
+ @source = node.source_string if node.source_string
261
+ @target = node.target_string if node.target_string
262
+ return node.targets[0] if node.targets&.any?
263
+
264
+ node.sources[0] if node.sources&.any?
265
+ end
266
+
267
+ # @raise [ArgumentError]
268
+ def validate_base
269
+ raise(ArgumentError, "#{ self } did not have a proper action. Unable to continue.") unless action
270
+ raise(ArgumentError, "#{ self } did not have a proper eventId. Unable to continue.") unless event_id
271
+ raise(ArgumentError, "#{ self } did not have a proper thread. Unable to continue.") unless thread
272
+ raise(ArgumentError, "#{ self } did not have a proper time. Unable to continue.") unless time
273
+ raise(ArgumentError, "#{ self } did not have a proper type. Unable to continue.") unless type
274
+ end
275
+
276
+ # @raise [ArgumentError]
277
+ def validate_dataflow
278
+ unless parent_object_ids
279
+ raise(ArgumentError, "#{ self } did not have a proper parentObjectIds. Unable to continue.")
280
+ end
281
+ unless taint_ranges && !taint_ranges.empty?
282
+ raise(ArgumentError, "#{ self } did not have a proper taintRanges. Unable to continue.")
283
+ end
284
+ raise(ArgumentError, "#{ self } did not have a proper args. Unable to continue.") unless args
285
+ raise(ArgumentError, "#{ self } did not have a proper object. Unable to continue.") unless object
286
+ raise(ArgumentError, "#{ self } did not have a proper signature. Unable to continue.") unless signature
287
+ raise(ArgumentError, "#{ self } did not have a proper stack. Unable to continue.") unless stack
288
+ raise(ArgumentError, "#{ self } did not have a proper tags. Unable to continue.") unless tags && !tags.empty?
289
+ end
290
+ end
291
+ end
292
+ end
293
+ end
@@ -0,0 +1,94 @@
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 'base64'
5
+ require 'contrast/agent/assess/contrast_object'
6
+
7
+ module Contrast
8
+ module Agent
9
+ module Reporting
10
+ # This is the new FindingEventObject class which will include all the needed information for the new reporting
11
+ # system to relay this information in the Finding/Trace messages. These FindingEventObjects are used by
12
+ # TeamServer to construct the vulnerability information for the assess feature. They represent those parts of the
13
+ # objects that were acted on in a Dataflow Finding.
14
+ class FindingEventObject
15
+ # @return [Integer] the id of the Object this represents.
16
+ attr_reader :hash
17
+ # @return [Boolean] if the Object is tracked or not
18
+ attr_reader :tracked
19
+ # @return [String] the base64 of the human readable representation of the Object this represents.
20
+ attr_reader :value
21
+
22
+ # We'll truncate any object that isn't important to the taint ranges of this event, so that we don't murder
23
+ # TeamServer by, for instance, hypothetically sending the entire rendered HTML page >_> <_< >_>
24
+ ELLIPSIS = '...'
25
+ UNTRUNCATED_PORTION_LENGTH = 25
26
+ TRUNCATION_LENGTH = (UNTRUNCATED_PORTION_LENGTH * 2) + ELLIPSIS.length
27
+
28
+ class << self
29
+ # @param object [Contrast::Agent::Assess::ContrastObject] the object to translate
30
+ # @param truncate [Boolean] if the value of this FindingEventObject should be truncated or not
31
+ # @return [Contrast::Agent::Reporting::FindingEventObject]
32
+ def convert object, truncate
33
+ report = new
34
+ report.attach_data(object, truncate)
35
+ report
36
+ end
37
+ end
38
+
39
+ # Parse the data from a Contrast::Agent::Assess::ContrastObject to attach what is required for reporting to
40
+ # TeamServer to this Contrast::Agent::Reporting::FindingEventObject
41
+ #
42
+ # @param object [Contrast::Agent::Assess::ContrastObject, nil]
43
+ def attach_data object, truncate
44
+ @hash = object&.object.__id__
45
+ @tracked = !!object&.tracked?
46
+ @value = reportable_value(object&.object, truncate)
47
+ end
48
+
49
+ # Convert the instance variables on the class, and other information, into the identifiers required for
50
+ # TeamServer to process the JSON form of this message.
51
+ #
52
+ # @return [Hash]
53
+ # @raise [ArgumentError]
54
+ def to_controlled_hash
55
+ validate
56
+ {
57
+ hash: hash,
58
+ tracked: tracked,
59
+ value: value
60
+ }
61
+ end
62
+
63
+ def validate
64
+ raise(ArgumentError, "#{ self } did not have a proper hash. Unable to continue.") unless hash
65
+ raise(ArgumentError, "#{ self } did not have a proper tracked. Unable to continue.") if tracked.nil?
66
+ return if value
67
+
68
+ raise(ArgumentError, "#{ self } did not have a proper value. Unable to continue.")
69
+ end
70
+
71
+ private
72
+
73
+ # Parse, truncate, and translate the given value to be reported to TeamServer. The field is expected to be
74
+ # base64 encoded.
75
+ #
76
+ # @param value [String, nil] the contrast_string of the object this represents.
77
+ # @param truncate [Boolean] if the string should be truncated or not.
78
+ # @return [String]
79
+ def reportable_value value, truncate
80
+ return Contrast::Utils::ObjectShare::NIL_STRING unless value
81
+
82
+ if truncate && value.length > TRUNCATION_LENGTH
83
+ tmp = []
84
+ tmp << value[0, UNTRUNCATED_PORTION_LENGTH]
85
+ tmp << ELLIPSIS
86
+ tmp << value[value.length - UNTRUNCATED_PORTION_LENGTH, UNTRUNCATED_PORTION_LENGTH]
87
+ value = tmp.join
88
+ end
89
+ Base64.strict_encode64(value)
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end