contrast-agent 4.3.2 → 4.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (317) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +1 -1
  3. data/.simplecov +1 -1
  4. data/Gemfile +1 -1
  5. data/LICENSE.txt +1 -1
  6. data/Rakefile +2 -3
  7. data/exe/contrast_service +1 -1
  8. data/ext/build_funchook.rb +4 -4
  9. data/ext/cs__assess_active_record_named/cs__active_record_named.c +1 -1
  10. data/ext/cs__assess_active_record_named/extconf.rb +1 -1
  11. data/ext/cs__assess_array/cs__assess_array.c +1 -1
  12. data/ext/cs__assess_array/extconf.rb +1 -1
  13. data/ext/cs__assess_basic_object/cs__assess_basic_object.c +1 -1
  14. data/ext/cs__assess_basic_object/extconf.rb +1 -1
  15. data/ext/cs__assess_fiber_track/cs__assess_fiber_track.c +1 -1
  16. data/ext/cs__assess_fiber_track/extconf.rb +1 -1
  17. data/ext/cs__assess_hash/cs__assess_hash.c +4 -2
  18. data/ext/cs__assess_hash/extconf.rb +1 -1
  19. data/ext/cs__assess_kernel/cs__assess_kernel.c +1 -1
  20. data/ext/cs__assess_kernel/extconf.rb +1 -1
  21. data/ext/cs__assess_marshal_module/cs__assess_marshal_module.c +1 -1
  22. data/ext/cs__assess_marshal_module/extconf.rb +1 -1
  23. data/ext/cs__assess_module/cs__assess_module.c +1 -1
  24. data/ext/cs__assess_module/extconf.rb +1 -1
  25. data/ext/cs__assess_regexp/cs__assess_regexp.c +1 -1
  26. data/ext/cs__assess_regexp/extconf.rb +1 -1
  27. data/ext/cs__assess_string/cs__assess_string.c +1 -1
  28. data/ext/cs__assess_string/extconf.rb +1 -1
  29. data/ext/cs__assess_string_interpolation26/cs__assess_string_interpolation26.c +1 -1
  30. data/ext/cs__assess_string_interpolation26/extconf.rb +1 -1
  31. data/ext/cs__assess_yield_track/cs__assess_yield_track.c +1 -1
  32. data/ext/cs__assess_yield_track/extconf.rb +1 -1
  33. data/ext/cs__common/cs__common.c +5 -5
  34. data/ext/cs__common/cs__common.h +4 -4
  35. data/ext/cs__common/extconf.rb +1 -1
  36. data/ext/cs__contrast_patch/cs__contrast_patch.c +22 -25
  37. data/ext/cs__contrast_patch/extconf.rb +1 -1
  38. data/ext/cs__protect_kernel/cs__protect_kernel.c +1 -1
  39. data/ext/cs__protect_kernel/extconf.rb +1 -1
  40. data/ext/extconf_common.rb +2 -6
  41. data/lib/contrast-agent.rb +1 -1
  42. data/lib/contrast.rb +20 -1
  43. data/lib/contrast/agent.rb +6 -4
  44. data/lib/contrast/agent/assess.rb +2 -11
  45. data/lib/contrast/agent/assess/contrast_event.rb +54 -71
  46. data/lib/contrast/agent/assess/contrast_object.rb +7 -4
  47. data/lib/contrast/agent/assess/events/event_factory.rb +3 -2
  48. data/lib/contrast/agent/assess/events/source_event.rb +7 -2
  49. data/lib/contrast/agent/assess/finalizers/freeze.rb +1 -1
  50. data/lib/contrast/agent/assess/finalizers/hash.rb +33 -34
  51. data/lib/contrast/agent/assess/policy/dynamic_source_factory.rb +34 -16
  52. data/lib/contrast/agent/assess/policy/patcher.rb +11 -18
  53. data/lib/contrast/agent/assess/policy/policy.rb +1 -1
  54. data/lib/contrast/agent/assess/policy/policy_node.rb +26 -34
  55. data/lib/contrast/agent/assess/policy/policy_scanner.rb +1 -1
  56. data/lib/contrast/agent/assess/policy/preshift.rb +4 -2
  57. data/lib/contrast/agent/assess/policy/propagation_method.rb +32 -30
  58. data/lib/contrast/agent/assess/policy/propagation_node.rb +20 -9
  59. data/lib/contrast/agent/assess/policy/propagator.rb +1 -1
  60. data/lib/contrast/agent/assess/policy/propagator/append.rb +29 -14
  61. data/lib/contrast/agent/assess/policy/propagator/base.rb +1 -1
  62. data/lib/contrast/agent/assess/policy/propagator/center.rb +3 -2
  63. data/lib/contrast/agent/assess/policy/propagator/custom.rb +1 -1
  64. data/lib/contrast/agent/assess/policy/propagator/database_write.rb +22 -17
  65. data/lib/contrast/agent/assess/policy/propagator/insert.rb +4 -2
  66. data/lib/contrast/agent/assess/policy/propagator/keep.rb +1 -1
  67. data/lib/contrast/agent/assess/policy/propagator/match_data.rb +3 -2
  68. data/lib/contrast/agent/assess/policy/propagator/next.rb +1 -1
  69. data/lib/contrast/agent/assess/policy/propagator/prepend.rb +1 -1
  70. data/lib/contrast/agent/assess/policy/propagator/remove.rb +23 -19
  71. data/lib/contrast/agent/assess/policy/propagator/replace.rb +1 -1
  72. data/lib/contrast/agent/assess/policy/propagator/reverse.rb +1 -1
  73. data/lib/contrast/agent/assess/policy/propagator/select.rb +3 -13
  74. data/lib/contrast/agent/assess/policy/propagator/splat.rb +24 -14
  75. data/lib/contrast/agent/assess/policy/propagator/split.rb +18 -15
  76. data/lib/contrast/agent/assess/policy/propagator/substitution.rb +32 -22
  77. data/lib/contrast/agent/assess/policy/propagator/trim.rb +64 -45
  78. data/lib/contrast/agent/assess/policy/rewriter_patch.rb +7 -4
  79. data/lib/contrast/agent/assess/policy/source_method.rb +92 -81
  80. data/lib/contrast/agent/assess/policy/source_node.rb +1 -1
  81. data/lib/contrast/agent/assess/policy/source_validation/cross_site_validator.rb +8 -6
  82. data/lib/contrast/agent/assess/policy/source_validation/source_validation.rb +2 -4
  83. data/lib/contrast/agent/assess/policy/trigger/reflected_xss.rb +7 -3
  84. data/lib/contrast/agent/assess/policy/trigger/xpath.rb +7 -8
  85. data/lib/contrast/agent/assess/policy/trigger_method.rb +109 -76
  86. data/lib/contrast/agent/assess/policy/trigger_node.rb +33 -11
  87. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +60 -0
  88. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +3 -5
  89. data/lib/contrast/agent/assess/policy/trigger_validation/trigger_validation.rb +7 -5
  90. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +4 -13
  91. data/lib/contrast/agent/assess/properties.rb +1 -3
  92. data/lib/contrast/agent/assess/property/evented.rb +9 -6
  93. data/lib/contrast/agent/assess/property/tagged.rb +38 -20
  94. data/lib/contrast/agent/assess/property/updated.rb +1 -1
  95. data/lib/contrast/agent/assess/rule/provider.rb +1 -1
  96. data/lib/contrast/agent/assess/rule/provider/hardcoded_key.rb +12 -6
  97. data/lib/contrast/agent/assess/rule/provider/hardcoded_password.rb +5 -2
  98. data/lib/contrast/agent/assess/rule/provider/hardcoded_value_rule.rb +4 -6
  99. data/lib/contrast/agent/assess/tag.rb +1 -1
  100. data/lib/contrast/agent/assess/tracker.rb +2 -2
  101. data/lib/contrast/agent/at_exit_hook.rb +1 -1
  102. data/lib/contrast/agent/class_reopener.rb +4 -2
  103. data/lib/contrast/agent/deadzone/policy/deadzone_node.rb +1 -1
  104. data/lib/contrast/agent/deadzone/policy/policy.rb +7 -3
  105. data/lib/contrast/agent/disable_reaction.rb +2 -4
  106. data/lib/contrast/agent/exclusion_matcher.rb +6 -12
  107. data/lib/contrast/agent/inventory.rb +1 -2
  108. data/lib/contrast/agent/inventory/dependencies.rb +3 -1
  109. data/lib/contrast/agent/inventory/dependency_analysis.rb +1 -1
  110. data/lib/contrast/agent/inventory/dependency_usage_analysis.rb +35 -23
  111. data/lib/contrast/agent/inventory/policy/datastores.rb +1 -1
  112. data/lib/contrast/agent/inventory/policy/policy.rb +1 -1
  113. data/lib/contrast/agent/inventory/policy/trigger_node.rb +1 -1
  114. data/lib/contrast/agent/middleware.rb +111 -110
  115. data/lib/contrast/agent/module_data.rb +4 -4
  116. data/lib/contrast/agent/patching/policy/after_load_patch.rb +1 -1
  117. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +9 -4
  118. data/lib/contrast/agent/patching/policy/method_policy.rb +7 -3
  119. data/lib/contrast/agent/patching/policy/module_policy.rb +15 -8
  120. data/lib/contrast/agent/patching/policy/patch.rb +23 -29
  121. data/lib/contrast/agent/patching/policy/patch_status.rb +8 -9
  122. data/lib/contrast/agent/patching/policy/patcher.rb +72 -64
  123. data/lib/contrast/agent/patching/policy/policy.rb +14 -21
  124. data/lib/contrast/agent/patching/policy/policy_node.rb +15 -5
  125. data/lib/contrast/agent/patching/policy/trigger_node.rb +26 -10
  126. data/lib/contrast/agent/protect/policy/applies_command_injection_rule.rb +2 -2
  127. data/lib/contrast/agent/protect/policy/applies_deserialization_rule.rb +2 -2
  128. data/lib/contrast/agent/protect/policy/applies_no_sqli_rule.rb +2 -2
  129. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +3 -4
  130. data/lib/contrast/agent/protect/policy/applies_sqli_rule.rb +2 -2
  131. data/lib/contrast/agent/protect/policy/applies_xxe_rule.rb +6 -10
  132. data/lib/contrast/agent/protect/policy/policy.rb +1 -1
  133. data/lib/contrast/agent/protect/policy/rule_applicator.rb +6 -6
  134. data/lib/contrast/agent/protect/policy/trigger_node.rb +1 -1
  135. data/lib/contrast/agent/protect/rule.rb +1 -1
  136. data/lib/contrast/agent/protect/rule/base.rb +19 -33
  137. data/lib/contrast/agent/protect/rule/base_service.rb +10 -6
  138. data/lib/contrast/agent/protect/rule/cmd_injection.rb +15 -19
  139. data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -1
  140. data/lib/contrast/agent/protect/rule/deserialization.rb +7 -14
  141. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +4 -15
  142. data/lib/contrast/agent/protect/rule/no_sqli.rb +7 -3
  143. data/lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb +2 -4
  144. data/lib/contrast/agent/protect/rule/path_traversal.rb +6 -6
  145. data/lib/contrast/agent/protect/rule/sqli.rb +19 -13
  146. data/lib/contrast/agent/protect/rule/sqli/default_sql_scanner.rb +1 -1
  147. data/lib/contrast/agent/protect/rule/sqli/mysql_sql_scanner.rb +1 -1
  148. data/lib/contrast/agent/protect/rule/sqli/postgres_sql_scanner.rb +2 -2
  149. data/lib/contrast/agent/protect/rule/sqli/sqlite_sql_scanner.rb +1 -1
  150. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +2 -2
  151. data/lib/contrast/agent/protect/rule/xss.rb +2 -2
  152. data/lib/contrast/agent/protect/rule/xxe.rb +6 -13
  153. data/lib/contrast/agent/protect/rule/xxe/entity_wrapper.rb +2 -3
  154. data/lib/contrast/agent/railtie.rb +1 -1
  155. data/lib/contrast/agent/reaction_processor.rb +12 -11
  156. data/lib/contrast/agent/request.rb +25 -24
  157. data/lib/contrast/agent/request_context.rb +25 -23
  158. data/lib/contrast/agent/request_handler.rb +1 -1
  159. data/lib/contrast/agent/response.rb +1 -1
  160. data/lib/contrast/agent/rewriter.rb +6 -4
  161. data/lib/contrast/agent/rule_set.rb +3 -3
  162. data/lib/contrast/agent/scope.rb +1 -1
  163. data/lib/contrast/agent/service_heartbeat.rb +3 -4
  164. data/lib/contrast/agent/static_analysis.rb +1 -1
  165. data/lib/contrast/agent/thread.rb +2 -2
  166. data/lib/contrast/agent/thread_watcher.rb +21 -6
  167. data/lib/contrast/agent/tracepoint_hook.rb +2 -2
  168. data/lib/contrast/agent/version.rb +2 -2
  169. data/lib/contrast/agent/worker_thread.rb +1 -1
  170. data/lib/contrast/api.rb +1 -1
  171. data/lib/contrast/api/communication.rb +1 -1
  172. data/lib/contrast/api/communication/connection_status.rb +1 -1
  173. data/lib/contrast/api/communication/messaging_queue.rb +19 -22
  174. data/lib/contrast/api/communication/response_processor.rb +13 -8
  175. data/lib/contrast/api/communication/service_lifecycle.rb +5 -3
  176. data/lib/contrast/api/communication/socket.rb +1 -1
  177. data/lib/contrast/api/communication/socket_client.rb +30 -35
  178. data/lib/contrast/api/communication/speedracer.rb +6 -10
  179. data/lib/contrast/api/communication/tcp_socket.rb +1 -1
  180. data/lib/contrast/api/communication/unix_socket.rb +1 -1
  181. data/lib/contrast/api/decorators.rb +3 -1
  182. data/lib/contrast/api/decorators/address.rb +1 -1
  183. data/lib/contrast/api/decorators/agent_startup.rb +58 -0
  184. data/lib/contrast/api/decorators/application_settings.rb +1 -1
  185. data/lib/contrast/api/decorators/application_startup.rb +57 -0
  186. data/lib/contrast/api/decorators/application_update.rb +1 -1
  187. data/lib/contrast/api/decorators/http_request.rb +1 -1
  188. data/lib/contrast/api/decorators/input_analysis.rb +1 -1
  189. data/lib/contrast/api/decorators/instrumentation_mode.rb +37 -0
  190. data/lib/contrast/api/decorators/library.rb +9 -7
  191. data/lib/contrast/api/decorators/library_usage_update.rb +1 -1
  192. data/lib/contrast/api/decorators/message.rb +4 -4
  193. data/lib/contrast/api/decorators/rasp_rule_sample.rb +1 -1
  194. data/lib/contrast/api/decorators/route_coverage.rb +16 -6
  195. data/lib/contrast/api/decorators/server_features.rb +1 -1
  196. data/lib/contrast/api/decorators/trace_event.rb +46 -16
  197. data/lib/contrast/api/decorators/trace_event_object.rb +2 -4
  198. data/lib/contrast/api/decorators/trace_event_signature.rb +1 -1
  199. data/lib/contrast/api/decorators/trace_taint_range.rb +1 -1
  200. data/lib/contrast/api/decorators/trace_taint_range_tags.rb +2 -7
  201. data/lib/contrast/api/decorators/user_input.rb +1 -1
  202. data/lib/contrast/components/agent.rb +16 -15
  203. data/lib/contrast/components/app_context.rb +11 -29
  204. data/lib/contrast/components/assess.rb +6 -11
  205. data/lib/contrast/components/config.rb +3 -2
  206. data/lib/contrast/components/contrast_service.rb +8 -9
  207. data/lib/contrast/components/heap_dump.rb +1 -1
  208. data/lib/contrast/components/interface.rb +4 -3
  209. data/lib/contrast/components/inventory.rb +1 -1
  210. data/lib/contrast/components/logger.rb +1 -1
  211. data/lib/contrast/components/protect.rb +11 -14
  212. data/lib/contrast/components/sampling.rb +55 -7
  213. data/lib/contrast/components/scope.rb +2 -1
  214. data/lib/contrast/components/settings.rb +29 -99
  215. data/lib/contrast/config.rb +1 -1
  216. data/lib/contrast/config/agent_configuration.rb +1 -1
  217. data/lib/contrast/config/application_configuration.rb +1 -1
  218. data/lib/contrast/config/assess_configuration.rb +1 -1
  219. data/lib/contrast/config/assess_rules_configuration.rb +2 -4
  220. data/lib/contrast/config/base_configuration.rb +5 -6
  221. data/lib/contrast/config/default_value.rb +1 -1
  222. data/lib/contrast/config/exception_configuration.rb +2 -6
  223. data/lib/contrast/config/heap_dump_configuration.rb +13 -7
  224. data/lib/contrast/config/inventory_configuration.rb +1 -1
  225. data/lib/contrast/config/logger_configuration.rb +2 -6
  226. data/lib/contrast/config/protect_configuration.rb +1 -1
  227. data/lib/contrast/config/protect_rule_configuration.rb +23 -1
  228. data/lib/contrast/config/protect_rules_configuration.rb +1 -1
  229. data/lib/contrast/config/root_configuration.rb +1 -1
  230. data/lib/contrast/config/ruby_configuration.rb +1 -1
  231. data/lib/contrast/config/sampling_configuration.rb +1 -1
  232. data/lib/contrast/config/server_configuration.rb +1 -1
  233. data/lib/contrast/config/service_configuration.rb +1 -1
  234. data/lib/contrast/configuration.rb +4 -15
  235. data/lib/contrast/delegators/input_analysis.rb +12 -0
  236. data/lib/contrast/extension/assess.rb +1 -1
  237. data/lib/contrast/extension/assess/array.rb +2 -7
  238. data/lib/contrast/extension/assess/erb.rb +2 -8
  239. data/lib/contrast/extension/assess/eval_trigger.rb +3 -11
  240. data/lib/contrast/extension/assess/exec_trigger.rb +4 -14
  241. data/lib/contrast/extension/assess/fiber.rb +3 -13
  242. data/lib/contrast/extension/assess/hash.rb +1 -1
  243. data/lib/contrast/extension/assess/kernel.rb +3 -10
  244. data/lib/contrast/extension/assess/marshal.rb +3 -11
  245. data/lib/contrast/extension/assess/regexp.rb +2 -7
  246. data/lib/contrast/extension/assess/string.rb +4 -2
  247. data/lib/contrast/extension/delegator.rb +1 -1
  248. data/lib/contrast/extension/inventory.rb +1 -1
  249. data/lib/contrast/extension/kernel.rb +5 -3
  250. data/lib/contrast/extension/module.rb +1 -1
  251. data/lib/contrast/extension/protect.rb +1 -1
  252. data/lib/contrast/extension/protect/kernel.rb +1 -1
  253. data/lib/contrast/extension/protect/psych.rb +1 -1
  254. data/lib/contrast/extension/thread.rb +1 -1
  255. data/lib/contrast/framework/base_support.rb +1 -1
  256. data/lib/contrast/framework/manager.rb +14 -17
  257. data/lib/contrast/framework/platform_version.rb +1 -1
  258. data/lib/contrast/framework/rack/patch/session_cookie.rb +6 -19
  259. data/lib/contrast/framework/rack/patch/support.rb +7 -5
  260. data/lib/contrast/framework/rack/support.rb +1 -1
  261. data/lib/contrast/framework/rails/patch/action_controller_live_buffer.rb +1 -1
  262. data/lib/contrast/framework/rails/patch/assess_configuration.rb +8 -3
  263. data/lib/contrast/framework/rails/patch/rails_application_configuration.rb +4 -4
  264. data/lib/contrast/framework/rails/patch/support.rb +5 -3
  265. data/lib/contrast/framework/rails/rewrite/action_controller_railties_helper_inherited.rb +5 -2
  266. data/lib/contrast/framework/rails/rewrite/active_record_attribute_methods_read.rb +3 -1
  267. data/lib/contrast/framework/rails/rewrite/active_record_named.rb +3 -1
  268. data/lib/contrast/framework/rails/rewrite/active_record_time_zone_inherited.rb +3 -1
  269. data/lib/contrast/framework/rails/support.rb +45 -46
  270. data/lib/contrast/framework/sinatra/support.rb +103 -42
  271. data/lib/contrast/funchook/funchook.rb +2 -6
  272. data/lib/contrast/logger/application.rb +13 -10
  273. data/lib/contrast/logger/format.rb +3 -6
  274. data/lib/contrast/logger/log.rb +36 -19
  275. data/lib/contrast/logger/request.rb +2 -3
  276. data/lib/contrast/logger/time.rb +1 -1
  277. data/lib/contrast/security_exception.rb +2 -2
  278. data/lib/contrast/tasks/config.rb +1 -1
  279. data/lib/contrast/tasks/service.rb +6 -2
  280. data/lib/contrast/utils/assess/sampling_util.rb +1 -1
  281. data/lib/contrast/utils/assess/tracking_util.rb +2 -3
  282. data/lib/contrast/utils/class_util.rb +18 -12
  283. data/lib/contrast/utils/duck_utils.rb +1 -1
  284. data/lib/contrast/utils/env_configuration_item.rb +1 -1
  285. data/lib/contrast/utils/hash_digest.rb +16 -24
  286. data/lib/contrast/utils/heap_dump_util.rb +104 -88
  287. data/lib/contrast/utils/invalid_configuration_util.rb +22 -13
  288. data/lib/contrast/utils/inventory_util.rb +1 -1
  289. data/lib/contrast/utils/io_util.rb +2 -2
  290. data/lib/contrast/utils/job_servers_running.rb +10 -5
  291. data/lib/contrast/utils/object_share.rb +1 -1
  292. data/lib/contrast/utils/os.rb +3 -2
  293. data/lib/contrast/utils/preflight_util.rb +1 -1
  294. data/lib/contrast/utils/resource_loader.rb +1 -1
  295. data/lib/contrast/utils/ruby_ast_rewriter.rb +3 -2
  296. data/lib/contrast/utils/sha256_builder.rb +1 -1
  297. data/lib/contrast/utils/stack_trace_utils.rb +1 -1
  298. data/lib/contrast/utils/string_utils.rb +1 -1
  299. data/lib/contrast/utils/tag_util.rb +1 -1
  300. data/lib/contrast/utils/thread_tracker.rb +1 -1
  301. data/lib/contrast/utils/timer.rb +1 -1
  302. data/resources/assess/policy.json +8 -11
  303. data/resources/deadzone/policy.json +7 -17
  304. data/ruby-agent.gemspec +66 -27
  305. data/service_executables/VERSION +1 -1
  306. data/service_executables/linux/contrast-service +0 -0
  307. data/service_executables/mac/contrast-service +0 -0
  308. data/sonar-project.properties +9 -0
  309. metadata +154 -156
  310. data/lib/contrast/agent/assess/rule.rb +0 -18
  311. data/lib/contrast/agent/assess/rule/base.rb +0 -52
  312. data/lib/contrast/agent/assess/rule/redos.rb +0 -67
  313. data/lib/contrast/agent/inventory/gemfile_digest_cache.rb +0 -38
  314. data/lib/contrast/common_agent_configuration.rb +0 -87
  315. data/lib/contrast/framework/sinatra/patch/base.rb +0 -83
  316. data/lib/contrast/framework/sinatra/patch/support.rb +0 -27
  317. data/lib/contrast/utils/prevent_serialization.rb +0 -52
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Contrast
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 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 'contrast/agent/assess/policy/source_method'
@@ -8,11 +8,13 @@ module Contrast
8
8
  module Assess
9
9
  module Policy
10
10
  module SourceValidation
11
- # Validator used to assert a CROSS_SITE tag is actually applicable to
12
- # the given method before applying the tag to its target
11
+ # Validator used to assert a CROSS_SITE tag is actually applicable to the given method before applying the
12
+ # tag to its target
13
13
  module CrossSiteValidator
14
- # prevent the application of a tag if it is from a source known to
15
- # not apply a tag in a provided context.
14
+ # Prevent the application of a tag if it is from a source known to not apply a tag in a provided context.
15
+ # Note that for Rack, the Header will be HTTP_REFERER. Rails does some help in
16
+ # ActionDispatch::Http::Headers to convert keys like `referer` to `HTTP_REFERER` before they get to the
17
+ # Rack::Request#get_header method
16
18
  # https://bitbucket.org/contrastsecurity/assess-specifications/src/master/rules/dataflow/reflected_xss.md
17
19
  def self.valid? tag, source_type, source_name
18
20
  return true unless tag == 'CROSS_SITE'
@@ -20,7 +22,7 @@ module Contrast
20
22
  return true unless source_type == Contrast::Agent::Assess::Policy::SourceMethod::HEADER_TYPE
21
23
  return false unless source_name
22
24
 
23
- source_name.casecmp?('referer')
25
+ source_name == 'HTTP_REFERER'
24
26
  end
25
27
  end
26
28
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 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 'contrast/agent/assess/policy/source_validation/cross_site_validator'
@@ -11,9 +11,7 @@ module Contrast
11
11
  # certain tags in a given context. This provides a single place from
12
12
  # which those validations can be called.
13
13
  module SourceValidation
14
- VALIDATORS = [
15
- Contrast::Agent::Assess::Policy::SourceValidation::CrossSiteValidator
16
- ].cs__freeze
14
+ VALIDATORS = [Contrast::Agent::Assess::Policy::SourceValidation::CrossSiteValidator].cs__freeze
17
15
 
18
16
  # Determines if the conditions in which this source was called are
19
17
  # valid and should result in the application of a tag
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Contrast
@@ -24,7 +24,7 @@ module Contrast
24
24
  }.cs__freeze
25
25
  TEMPLATE_PROPAGATION_NODE = Contrast::Agent::Assess::Policy::PropagationNode.new(NODE_HASH)
26
26
 
27
- def xss_tilt_trigger context, trigger_node, _source, object, ret, *args
27
+ def xss_tilt_trigger trigger_node, _source, object, ret, *args
28
28
  return unless (properties = Contrast::Agent::Assess::Tracker.properties!(ret))
29
29
 
30
30
  scope = args[0]
@@ -44,7 +44,11 @@ module Contrast
44
44
  end
45
45
 
46
46
  if Contrast::Agent::Assess::Tracker.tracked?(ret)
47
- Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(context, trigger_node, ret, erb_template_prerender, ret, interpolated_inputs)
47
+ Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(trigger_node,
48
+ ret,
49
+ erb_template_prerender,
50
+ ret,
51
+ interpolated_inputs)
48
52
  end
49
53
 
50
54
  ret
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 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 'contrast/components/interface'
@@ -19,31 +19,30 @@ module Contrast
19
19
  include Contrast::Components::Interface
20
20
 
21
21
  class << self
22
- def xpath_expression_trigger context, trigger_node, _source, object, ret, *args
22
+ def xpath_expression_trigger trigger_node, _source, object, ret, *args
23
23
  return ret unless args
24
24
 
25
- process(context, trigger_node, object, ret, *args)
25
+ process(trigger_node, object, ret, *args)
26
26
  end
27
27
 
28
- def xpath_oga_trigger context, trigger_node, _source, object, ret, *args
28
+ def xpath_oga_trigger trigger_node, _source, object, ret, *args
29
29
  return ret unless args
30
30
 
31
31
  # convert the options arg in Oga::XML::CharacterNode#initialize into an
32
32
  # array of its values so we can check if any are unsafe
33
33
  args = args.first.values if args.first.cs__is_a?(Hash)
34
- process(context, trigger_node, object, ret, *args)
34
+ process(trigger_node, object, ret, *args)
35
35
  end
36
36
 
37
37
  private
38
38
 
39
- def process context, trigger_node, object, ret, *args
39
+ def process trigger_node, object, ret, *args
40
40
  args.each do |arg|
41
41
  next unless arg.cs__is_a?(String) || arg.cs__is_a?(Symbol)
42
42
  next unless Contrast::Agent::Assess::Tracker.tracked?(arg)
43
43
  next unless trigger_node.violated?(arg)
44
44
 
45
- Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(
46
- context, trigger_node, arg, object, ret, *args)
45
+ Contrast::Agent::Assess::Policy::TriggerMethod.build_finding(trigger_node, arg, object, ret, *args)
47
46
  end
48
47
 
49
48
  ret
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 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 'contrast/agent/assess/events/event_factory'
@@ -27,24 +27,6 @@ module Contrast
27
27
  CURRENT_FINDING_VERSION = 4
28
28
 
29
29
  class << self
30
- # Append the given finding to the given context to be reported when
31
- # the Context's activity is sent to the Service or, in the absence
32
- # of that Context, generate an Activity and queue it manually
33
- # @param finding [Contrast::Api::Dtm::Finding]
34
- def report_finding finding
35
- context = Contrast::Agent::REQUEST_TRACKER.current
36
- if context
37
- context.activity.findings << finding
38
- else
39
- activity = Contrast::Api::Dtm::Activity.new
40
- activity.findings << finding
41
-
42
- Contrast::Agent.messaging_queue.send_event_eventually(activity)
43
- end
44
- logger.debug('Finding reported',
45
- rule: finding.rule_id)
46
- end
47
-
48
30
  # This is called from within our woven proc. It will be called as if it
49
31
  # were inline in the Rack application.
50
32
  #
@@ -57,38 +39,23 @@ module Contrast
57
39
  def apply_trigger_rule trigger_node, object, ret, args
58
40
  return if trigger_node.nil?
59
41
 
60
- current_context = Contrast::Agent::REQUEST_TRACKER.current
61
- return unless current_context&.analyze_request? && ASSESS.enabled?
62
-
63
42
  if trigger_node.sources&.any?
64
43
  trigger_node.sources.each do |marker|
65
44
  source = determine_source(marker, object, ret, args)
66
- apply_trigger(current_context,
67
- trigger_node,
68
- source,
69
- object,
70
- ret,
71
- *args)
45
+ apply_trigger(trigger_node, source, object, ret, *args)
72
46
  end
73
47
  else
74
- apply_trigger(current_context,
75
- trigger_node,
76
- nil,
77
- object,
78
- ret,
79
- *args)
48
+ apply_trigger(trigger_node, nil, object, ret, *args)
80
49
  end
81
50
  end
82
51
 
83
- def apply_eval_trigger context, trigger_node, source, object, ret, *args
84
- apply_trigger(context, trigger_node, source, object, ret, *args)
52
+ def apply_eval_trigger trigger_node, source, object, ret, *args
53
+ apply_trigger(trigger_node, source, object, ret, *args)
85
54
  end
86
55
 
87
56
  # This converts the source of the finding, and the events leading
88
57
  # up to it into a Finding
89
58
  #
90
- # @param context [Contrast::Agent::RequestContext] the current
91
- # request context
92
59
  # @param trigger_node [Contrast::Agent::Assess::Policy::TriggerNode]
93
60
  # the node to direct applying this trigger event
94
61
  # @param source [Object] the source of the Trigger Event
@@ -99,39 +66,94 @@ module Contrast
99
66
  # @return [Contrast::Api::Dtm::Finding, nil] the
100
67
  # Contrast::Api::Dtm::Finding to send to TeamServer or nil if
101
68
  # conditions were not met
102
- def build_finding context, trigger_node, source, object, ret, *args
69
+ def build_finding trigger_node, source, object, ret, *args
103
70
  return unless Contrast::Agent::Assess::Policy::TriggerValidation.valid?(trigger_node, object, ret, args)
104
71
 
105
- request = context.request
106
- env = request.env
107
- return if defined?(ActionController::Live) &&
108
- env &&
109
- env['action_controller.instance'].cs__class.included_modules.include?(ActionController::Live)
72
+ request = find_request(source)
73
+ return unless reportable?(request&.env)
110
74
 
111
75
  finding = Contrast::Api::Dtm::Finding.new
112
76
  finding.rule_id = Contrast::Utils::StringUtils.protobuf_safe_string(trigger_node.rule_id)
113
- build_from_source(finding, source)
114
- trigger_event = Contrast::Agent::Assess::Events::EventFactory.build(trigger_node, source, object, ret, args).to_dtm_event
115
- finding.events << trigger_event
116
- build_hash(finding, source)
117
- finding.routes << context.route if context.route
77
+
78
+ append_events(finding, trigger_node, source, object, ret, args)
79
+ append_route(finding, request)
80
+ append_hash(finding, source, request)
118
81
  finding.version = determine_compliance_version(finding)
119
- logger.trace('Finding created',
120
- node_id: trigger_node.id,
121
- source_id: source.__id__,
122
- rule: trigger_node.rule_id)
123
- report_finding(finding)
82
+ logger.trace('Finding created', node_id: trigger_node.id, source_id: source.__id__,
83
+ rule: trigger_node.rule_id)
84
+ report_finding(finding, request)
124
85
  rescue StandardError => e
125
86
  logger.error('Unable to build a finding', e, rule: trigger_node.rule_id, node_id: trigger_node.id)
126
87
  end
127
88
 
89
+ # Given a finding, append it to an activity message and send it to
90
+ # the Service for processing.
91
+ #
92
+ # @param finding [Contrast::Api::Dtm::Finding] the Finding to
93
+ # report.
94
+ # @param request [Contrast::Agent::Request] our wrapper around the
95
+ # Rack::Request.
96
+ def report_finding finding, request = nil
97
+ context = Contrast::Agent::REQUEST_TRACKER.current
98
+ if context
99
+ context.activity.findings << finding
100
+ return
101
+ end
102
+
103
+ activity = Contrast::Api::Dtm::Activity.new
104
+ activity.findings << finding
105
+ if request
106
+ activity.http_request = request.dtm
107
+ else
108
+ logger.debug('Attempted to report finding without request', finding: finding)
109
+ end
110
+
111
+ # If we're out of request context, then we need to report this
112
+ # finding ourselves, so we'll send it in the one-off activity we
113
+ # created.
114
+ Contrast::Agent.messaging_queue.send_event_eventually(activity)
115
+ end
116
+
128
117
  private
129
118
 
119
+ # A request is reportable if it is not from ActionController::Live
120
+ #
121
+ # @param env [Hash] the env of the Request
122
+ # @return [Boolean]
123
+ def reportable? env
124
+ !(defined?(ActionController::Live) &&
125
+ env &&
126
+ env['action_controller.instance'].cs__class.included_modules.include?(ActionController::Live))
127
+ end
128
+
129
+ # Find the request for this finding. This assumes, for now, that if
130
+ # there is an active request, then that is the request to report.
131
+ # Otherwise, we'll use the first request found in the events of the
132
+ # source_object.
133
+ #
134
+ # @param source [Object,nil] some Object used as the source of a
135
+ # trigger event
136
+ # @return [Contrast::Agent::Request,nil] the request from which the
137
+ # dataflow on the request originated.
138
+ def find_request source
139
+ return Contrast::Agent::REQUEST_TRACKER.current.request if Contrast::Agent::REQUEST_TRACKER.current
140
+ return unless (properties = Contrast::Agent::Assess::Tracker.properties(source))
141
+
142
+ properties.events.each do |event|
143
+ next unless event.cs__is_a?(Contrast::Agent::Assess::Events::SourceEvent)
144
+
145
+ return event.request if event.request
146
+ end
147
+ nil
148
+ end
149
+
150
+ def settings
151
+ Contrast::Agent::FeatureState.instance
152
+ end
153
+
130
154
  # This is our method that actually checks the taint on the object
131
155
  # our trigger_node targets.
132
156
  #
133
- # @param context [Contrast::Agent::RequestContext] the current
134
- # request context
135
157
  # @param trigger_node [Contrast::Agent::Assess::Policy::TriggerNode]
136
158
  # the node to direct applying this trigger event
137
159
  # @param source [Object] the source of the Trigger Event
@@ -139,19 +161,19 @@ module Contrast
139
161
  # @param ret [Object] the Return of the invoked method
140
162
  # @param args [Array<Object>] the Arguments with which the method
141
163
  # was invoked
142
- def apply_trigger context, trigger_node, source, object, ret, *args
143
- return unless context && trigger_node
164
+ def apply_trigger trigger_node, source, object, ret, *args
165
+ return unless trigger_node
144
166
  return if trigger_node.rule_disabled?
145
167
  return if trigger_node.dataflow? && source.nil?
146
168
 
147
169
  if trigger_node.regexp_rule?
148
- apply_regexp_rule(context, trigger_node, source, object, ret, *args)
170
+ apply_regexp_rule(trigger_node, source, object, ret, *args)
149
171
  elsif trigger_node.custom_trigger?
150
- trigger_node.apply_custom_trigger(context, trigger_node, source, object, ret, *args)
172
+ trigger_node.apply_custom_trigger(trigger_node, source, object, ret, *args)
151
173
  elsif trigger_node.dataflow?
152
- apply_dataflow_rule(context, trigger_node, source, object, ret, *args)
174
+ apply_dataflow_rule(trigger_node, source, object, ret, *args)
153
175
  else # trigger rule - just calling the method is dangerous
154
- build_finding(context, trigger_node, source, object, ret, *args)
176
+ build_finding(trigger_node, source, object, ret, *args)
155
177
  end
156
178
  rescue StandardError => e
157
179
  logger.warn('Unable to apply trigger', e, node_id: trigger_node.id)
@@ -199,8 +221,6 @@ module Contrast
199
221
  # This is our method that actually checks the taint on the object
200
222
  # our trigger_node targets for our Regexp based rules.
201
223
  #
202
- # @param context [Contrast::Agent::RequestContext] the current
203
- # request context
204
224
  # @param trigger_node [Contrast::Agent::Assess::Policy::TriggerNode]
205
225
  # the node to direct applying this trigger event
206
226
  # @param source [Object] the source of the Trigger Event
@@ -208,19 +228,17 @@ module Contrast
208
228
  # @param ret [Object] the Return of the invoked method
209
229
  # @param args [Array<Object>] the Arguments with which the method
210
230
  # was invoked
211
- def apply_regexp_rule context, trigger_node, source, object, ret, *args
231
+ def apply_regexp_rule trigger_node, source, object, ret, *args
212
232
  return unless source.is_a?(String)
213
233
  return if trigger_node.good_value && source.match?(trigger_node.good_value)
214
234
  return if trigger_node.bad_value && source !~ trigger_node.bad_value
215
235
 
216
- build_finding(context, trigger_node, source, object, ret, *args)
236
+ build_finding(trigger_node, source, object, ret, *args)
217
237
  end
218
238
 
219
239
  # This is our method that actually checks the taint on the object
220
240
  # our trigger_node targets for our Dataflow based rules.
221
241
  #
222
- # @param context [Contrast::Agent::RequestContext] the current
223
- # request context
224
242
  # @param trigger_node [Contrast::Agent::Assess::Policy::TriggerNode]
225
243
  # the node to direct applying this trigger event
226
244
  # @param source [Object] the source of the Trigger Event
@@ -228,22 +246,22 @@ module Contrast
228
246
  # @param ret [Object] the Return of the invoked method
229
247
  # @param args [Array<Object>] the Arguments with which the method
230
248
  # was invoked
231
- def apply_dataflow_rule context, trigger_node, source, object, ret, *args
249
+ def apply_dataflow_rule trigger_node, source, object, ret, *args
232
250
  return unless source
233
251
 
234
252
  if Contrast::Agent::Assess::Tracker.trackable?(source)
235
253
  return unless Contrast::Agent::Assess::Tracker.tracked?(source)
236
254
  return unless trigger_node.violated?(source)
237
255
 
238
- build_finding(context, trigger_node, source, object, ret, *args)
256
+ build_finding(trigger_node, source, object, ret, *args)
239
257
  elsif Contrast::Utils::DuckUtils.iterable_hash?(source)
240
258
  source.each_pair do |key, value|
241
- apply_dataflow_rule(context, trigger_node, key, object, ret, *args)
242
- apply_dataflow_rule(context, trigger_node, value, object, ret, *args)
259
+ apply_dataflow_rule(trigger_node, key, object, ret, *args)
260
+ apply_dataflow_rule(trigger_node, value, object, ret, *args)
243
261
  end
244
262
  elsif Contrast::Utils::DuckUtils.iterable_enumerable?(source)
245
263
  source.each do |value|
246
- apply_dataflow_rule(context, trigger_node, value, object, ret, *args)
264
+ apply_dataflow_rule(trigger_node, value, object, ret, *args)
247
265
  end
248
266
  else
249
267
  logger.debug('Trigger source is untrackable. Unable to inspect.',
@@ -255,7 +273,13 @@ module Contrast
255
273
  end
256
274
  end
257
275
 
258
- def build_from_source finding, source
276
+ def append_events finding, trigger_node, source, object, ret, args
277
+ append_from_source(finding, source)
278
+ finding.events << Contrast::Agent::Assess::Events::EventFactory.build(trigger_node, source, object, ret,
279
+ args).to_dtm_event
280
+ end
281
+
282
+ def append_from_source finding, source
259
283
  return unless source
260
284
  return unless Contrast::Agent::Assess::Tracker.trackable?(source)
261
285
 
@@ -286,8 +310,17 @@ module Contrast
286
310
  finding.events << event.to_dtm_event
287
311
  end
288
312
 
289
- def build_hash finding, source
290
- hash_code = Contrast::Utils::HashDigest.generate_event_hash(finding, source)
313
+ def append_route finding, request
314
+ context = Contrast::Agent::REQUEST_TRACKER.current
315
+ if context
316
+ finding.routes << context.route if context.route
317
+ elsif request&.route
318
+ finding.routes << request.route
319
+ end
320
+ end
321
+
322
+ def append_hash finding, source, request
323
+ hash_code = Contrast::Utils::HashDigest.generate_event_hash(finding, source, request)
291
324
  finding.hash_code = Contrast::Utils::StringUtils.force_utf8(hash_code)
292
325
  finding.preflight = Contrast::Utils::PreflightUtil.create_preflight(finding)
293
326
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2020 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
1
+ # Copyright (c) 2021 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 'contrast/agent/assess/policy/trigger/reflected_xss'
@@ -47,8 +47,8 @@ module Contrast
47
47
  TRIGGER
48
48
  end
49
49
 
50
- def apply_custom_trigger context, trigger_node, source, object, ret, *args
51
- custom_trigger_class.send(@trigger_method, context, trigger_node, source, object, ret, *args)
50
+ def apply_custom_trigger trigger_node, source, object, ret, *args
51
+ custom_trigger_class.send(@trigger_method, trigger_node, source, object, ret, *args)
52
52
  end
53
53
 
54
54
  def custom_trigger_class
@@ -104,7 +104,8 @@ module Contrast
104
104
 
105
105
  properties = Contrast::Agent::Assess::Tracker.properties(source)
106
106
  # find the ranges that violate the rule (untrusted, etc)
107
- vulnerable_ranges = ranges_with_all_tags(Contrast::Utils::StringUtils.ret_length(source), properties, required_tags)
107
+ vulnerable_ranges = ranges_with_all_tags(Contrast::Utils::StringUtils.ret_length(source), properties,
108
+ required_tags)
108
109
  # if there aren't any vulnerable ranges, nope out
109
110
  return false if vulnerable_ranges.empty?
110
111
 
@@ -185,11 +186,7 @@ module Contrast
185
186
  # @return [Array<Contrast::Agent::Assess::Tag>] the ranges satisfied
186
187
  # by the given conditions
187
188
  def ranges_with_all_tags length, properties, required_tags
188
- # if there are no tags, not required tags, or the tags don't have
189
- # all the required tags, we can just return here.
190
- return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless properties.tracked?
191
- return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless required_tags&.any?
192
- return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless required_tags.all? { |tag| properties.tag_keys.include?(tag) }
189
+ return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless matches_tags?(properties, required_tags)
193
190
 
194
191
  ranges = []
195
192
  chunking = false
@@ -229,8 +226,7 @@ module Contrast
229
226
  # by the given conditions
230
227
  def ranges_with_any_tag properties, tags
231
228
  # if there aren't any all_tags or tags, break early
232
- return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless properties.tracked?
233
- return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless tags&.any?
229
+ return Contrast::Utils::ObjectShare::EMPTY_ARRAY unless search_tags?(properties, tags)
234
230
 
235
231
  ranges = []
236
232
  tags.each do |desired|
@@ -243,6 +239,32 @@ module Contrast
243
239
  end
244
240
  ranges
245
241
  end
242
+
243
+ # We should only try to match tags on properties if those properties have any tags (are tracked) and there
244
+ # are tags to try and match on. Some rules, like regexp rules, have no tags. Some rules, like trigger, have
245
+ # no properties.
246
+ #
247
+ # @param properties [Contrast::Agent::Assess::Properties] the properties to check for the tags
248
+ # @param tags [Set<String>] the list of tags on which to match
249
+ # @return [Boolean] if the given properties has instances of every tag in tags
250
+ def search_tags? properties, tags
251
+ return false unless properties.tracked?
252
+ return false unless tags&.any?
253
+
254
+ true
255
+ end
256
+
257
+ # Determine if the given properties have instances of all the given tags or not.
258
+ #
259
+ # @param properties [Contrast::Agent::Assess::Properties] the properties to check for the tags
260
+ # @param tags [Set<String>] the list of tags on which to match
261
+ # @return [Boolean] if the given properties has instances of every tag in tags
262
+ def matches_tags? properties, tags
263
+ return false unless search_tags?(properties, tags)
264
+ return false unless tags.all? { |tag| properties.tag_keys.include?(tag) }
265
+
266
+ true
267
+ end
246
268
  end
247
269
  end
248
270
  end