contrast-agent 6.7.0 → 6.8.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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -2
  3. data/.simplecov +0 -1
  4. data/Rakefile +0 -1
  5. data/ext/cs__assess_array/cs__assess_array.c +41 -10
  6. data/ext/cs__assess_array/cs__assess_array.h +4 -1
  7. data/lib/contrast/agent/assess/policy/trigger_method.rb +2 -2
  8. data/lib/contrast/agent/assess/policy/trigger_validation/redos_validator.rb +1 -1
  9. data/lib/contrast/agent/assess/policy/trigger_validation/ssrf_validator.rb +1 -1
  10. data/lib/contrast/agent/assess/policy/trigger_validation/xss_validator.rb +1 -1
  11. data/lib/contrast/agent/excluder.rb +52 -34
  12. data/lib/contrast/agent/exclusion_matcher.rb +21 -9
  13. data/lib/contrast/agent/middleware.rb +4 -4
  14. data/lib/contrast/agent/patching/policy/after_load_patcher.rb +6 -0
  15. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +146 -127
  16. data/lib/contrast/agent/protect/policy/applies_path_traversal_rule.rb +20 -0
  17. data/lib/contrast/agent/protect/policy/rule_applicator.rb +1 -1
  18. data/lib/contrast/agent/protect/rule/base.rb +45 -53
  19. data/lib/contrast/agent/protect/rule/base_service.rb +48 -24
  20. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +98 -0
  21. data/lib/contrast/agent/protect/rule/bot_blocker.rb +81 -0
  22. data/lib/contrast/agent/protect/rule/cmd_injection.rb +18 -1
  23. data/lib/contrast/agent/protect/rule/cmdi/cmdi_backdoors.rb +8 -5
  24. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +22 -22
  25. data/lib/contrast/agent/protect/rule/cmdi/cmdi_chained_command.rb +69 -0
  26. data/lib/contrast/agent/protect/rule/cmdi/cmdi_dangerous_path.rb +68 -0
  27. data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +2 -58
  28. data/lib/contrast/agent/protect/rule/default_scanner.rb +1 -1
  29. data/lib/contrast/agent/protect/rule/deserialization.rb +3 -14
  30. data/lib/contrast/agent/protect/rule/http_method_tampering/http_method_tampering_input_classification.rb +2 -2
  31. data/lib/contrast/agent/protect/rule/http_method_tampering.rb +0 -11
  32. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +29 -34
  33. data/lib/contrast/agent/protect/rule/no_sqli.rb +25 -18
  34. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_input_classification.rb +61 -0
  35. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_semantic_security_bypass.rb +114 -0
  36. data/lib/contrast/agent/protect/rule/path_traversal.rb +38 -12
  37. data/lib/contrast/agent/protect/rule/sql_sample_builder.rb +33 -15
  38. data/lib/contrast/agent/protect/rule/sqli/sqli_base_rule.rb +0 -14
  39. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +2 -62
  40. data/lib/contrast/agent/protect/rule/sqli.rb +70 -0
  41. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +39 -63
  42. data/lib/contrast/agent/protect/rule/unsafe_file_upload.rb +6 -33
  43. data/lib/contrast/agent/protect/rule/xss/reflected_xss_input_classification.rb +58 -0
  44. data/lib/contrast/agent/protect/rule/xss.rb +14 -20
  45. data/lib/contrast/agent/protect/rule/xxe.rb +4 -24
  46. data/lib/contrast/agent/reporting/attack_result/rasp_rule_sample.rb +18 -39
  47. data/lib/contrast/agent/reporting/attack_result/response_type.rb +9 -9
  48. data/lib/contrast/agent/reporting/details/ip_denylist_details.rb +10 -2
  49. data/lib/contrast/agent/reporting/details/virtual_patch_details.rb +8 -2
  50. data/lib/contrast/agent/reporting/input_analysis/details/bot_blocker_details.rb +27 -0
  51. data/lib/contrast/agent/reporting/input_analysis/details/protect_rule_details.rb +15 -0
  52. data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +1 -2
  53. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +16 -2
  54. data/lib/contrast/agent/reporting/masker/masker.rb +2 -0
  55. data/lib/contrast/agent/reporting/reporter.rb +1 -14
  56. data/lib/contrast/agent/reporting/reporting_events/application_activity.rb +15 -12
  57. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_activity.rb +3 -3
  58. data/lib/contrast/agent/reporting/reporting_events/application_defend_attack_sample.rb +1 -2
  59. data/lib/contrast/agent/reporting/reporting_events/application_update.rb +0 -2
  60. data/lib/contrast/agent/reporting/reporting_events/architecture_component.rb +0 -1
  61. data/lib/contrast/agent/reporting/reporting_events/finding.rb +4 -4
  62. data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +0 -5
  63. data/lib/contrast/agent/reporting/reporting_events/library_discovery.rb +0 -1
  64. data/lib/contrast/agent/reporting/reporting_events/poll.rb +1 -11
  65. data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +0 -1
  66. data/lib/contrast/agent/reporting/reporting_events/route_discovery_observation.rb +0 -1
  67. data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +2 -2
  68. data/lib/contrast/agent/reporting/reporting_utilities/response.rb +1 -1
  69. data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +0 -3
  70. data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +1 -0
  71. data/lib/contrast/agent/reporting/settings/code_exclusion.rb +6 -1
  72. data/lib/contrast/agent/reporting/settings/exclusion_base.rb +18 -0
  73. data/lib/contrast/agent/reporting/settings/exclusions.rb +2 -1
  74. data/lib/contrast/agent/reporting/settings/input_exclusion.rb +9 -3
  75. data/lib/contrast/agent/reporting/settings/protect.rb +15 -15
  76. data/lib/contrast/agent/request.rb +2 -14
  77. data/lib/contrast/agent/request_context.rb +6 -9
  78. data/lib/contrast/agent/request_context_extend.rb +9 -148
  79. data/lib/contrast/agent/thread_watcher.rb +3 -18
  80. data/lib/contrast/agent/version.rb +1 -1
  81. data/lib/contrast/agent.rb +0 -11
  82. data/lib/contrast/agent_lib/api/command_injection.rb +46 -0
  83. data/lib/contrast/agent_lib/api/init.rb +101 -0
  84. data/lib/contrast/agent_lib/api/input_tracing.rb +267 -0
  85. data/lib/contrast/agent_lib/api/method_tempering.rb +29 -0
  86. data/lib/contrast/agent_lib/api/panic.rb +87 -0
  87. data/lib/contrast/agent_lib/api/path_semantic_file_security_bypass.rb +40 -0
  88. data/lib/contrast/agent_lib/interface.rb +260 -0
  89. data/lib/contrast/agent_lib/interface_base.rb +118 -0
  90. data/lib/contrast/agent_lib/return_types/eval_result.rb +44 -0
  91. data/lib/contrast/agent_lib/test.rb +29 -0
  92. data/lib/contrast/api/communication/connection_status.rb +5 -5
  93. data/lib/contrast/components/agent.rb +0 -14
  94. data/lib/contrast/components/app_context.rb +0 -2
  95. data/lib/contrast/components/app_context_extend.rb +0 -25
  96. data/lib/contrast/components/config.rb +1 -18
  97. data/lib/contrast/components/protect.rb +4 -1
  98. data/lib/contrast/components/ruby_component.rb +1 -1
  99. data/lib/contrast/components/settings.rb +37 -89
  100. data/lib/contrast/config/protect_rule_configuration.rb +7 -7
  101. data/lib/contrast/config/protect_rules_configuration.rb +20 -58
  102. data/lib/contrast/configuration.rb +1 -10
  103. data/lib/contrast/extension/assess/array.rb +9 -0
  104. data/lib/contrast/extension/delegator.rb +2 -0
  105. data/lib/contrast/framework/manager.rb +3 -1
  106. data/lib/contrast/framework/rails/railtie.rb +0 -1
  107. data/lib/contrast/framework/rails/support.rb +0 -1
  108. data/lib/contrast/tasks/config.rb +1 -8
  109. data/lib/contrast/utils/duck_utils.rb +1 -0
  110. data/lib/contrast/utils/input_classification_base.rb +156 -0
  111. data/lib/contrast/utils/os.rb +0 -20
  112. data/lib/contrast/utils/response_utils.rb +0 -16
  113. data/lib/contrast/utils/stack_trace_utils.rb +3 -15
  114. data/lib/contrast/utils/string_utils.rb +10 -7
  115. data/lib/contrast.rb +2 -3
  116. data/resources/protect/policy.json +1 -2
  117. data/ruby-agent.gemspec +2 -5
  118. metadata +42 -112
  119. data/exe/contrast_service +0 -23
  120. data/lib/contrast/agent/protect/rule/cmdi/cmdi_worth_watching.rb +0 -64
  121. data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +0 -118
  122. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_matcher.rb +0 -45
  123. data/lib/contrast/agent/reaction_processor.rb +0 -47
  124. data/lib/contrast/agent/service_heartbeat.rb +0 -35
  125. data/lib/contrast/api/communication/messaging_queue.rb +0 -128
  126. data/lib/contrast/api/communication/response_processor.rb +0 -90
  127. data/lib/contrast/api/communication/service_lifecycle.rb +0 -77
  128. data/lib/contrast/api/communication/socket.rb +0 -44
  129. data/lib/contrast/api/communication/socket_client.rb +0 -130
  130. data/lib/contrast/api/communication/speedracer.rb +0 -138
  131. data/lib/contrast/api/communication/tcp_socket.rb +0 -32
  132. data/lib/contrast/api/communication/unix_socket.rb +0 -28
  133. data/lib/contrast/api/communication.rb +0 -20
  134. data/lib/contrast/api/decorators/address.rb +0 -59
  135. data/lib/contrast/api/decorators/agent_startup.rb +0 -56
  136. data/lib/contrast/api/decorators/application_settings.rb +0 -43
  137. data/lib/contrast/api/decorators/application_startup.rb +0 -56
  138. data/lib/contrast/api/decorators/bot_blocker.rb +0 -37
  139. data/lib/contrast/api/decorators/http_request.rb +0 -137
  140. data/lib/contrast/api/decorators/input_analysis.rb +0 -18
  141. data/lib/contrast/api/decorators/instrumentation_mode.rb +0 -35
  142. data/lib/contrast/api/decorators/ip_denylist.rb +0 -37
  143. data/lib/contrast/api/decorators/message.rb +0 -67
  144. data/lib/contrast/api/decorators/rasp_rule_sample.rb +0 -52
  145. data/lib/contrast/api/decorators/response_type.rb +0 -17
  146. data/lib/contrast/api/decorators/server_features.rb +0 -25
  147. data/lib/contrast/api/decorators/user_input.rb +0 -51
  148. data/lib/contrast/api/decorators/virtual_patch.rb +0 -34
  149. data/lib/contrast/api/decorators.rb +0 -22
  150. data/lib/contrast/api/dtm.pb.rb +0 -363
  151. data/lib/contrast/api/settings.pb.rb +0 -500
  152. data/lib/contrast/api.rb +0 -16
  153. data/lib/contrast/components/contrast_service.rb +0 -88
  154. data/lib/contrast/components/service.rb +0 -55
  155. data/lib/contrast/tasks/service.rb +0 -84
  156. data/lib/contrast/utils/input_classification.rb +0 -73
  157. data/lib/protobuf/code_generator.rb +0 -129
  158. data/lib/protobuf/decoder.rb +0 -28
  159. data/lib/protobuf/deprecation.rb +0 -117
  160. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +0 -79
  161. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +0 -360
  162. data/lib/protobuf/descriptors.rb +0 -3
  163. data/lib/protobuf/encoder.rb +0 -11
  164. data/lib/protobuf/enum.rb +0 -365
  165. data/lib/protobuf/exceptions.rb +0 -9
  166. data/lib/protobuf/field/base_field.rb +0 -380
  167. data/lib/protobuf/field/base_field_object_definitions.rb +0 -504
  168. data/lib/protobuf/field/bool_field.rb +0 -64
  169. data/lib/protobuf/field/bytes_field.rb +0 -67
  170. data/lib/protobuf/field/double_field.rb +0 -25
  171. data/lib/protobuf/field/enum_field.rb +0 -56
  172. data/lib/protobuf/field/field_array.rb +0 -102
  173. data/lib/protobuf/field/field_hash.rb +0 -122
  174. data/lib/protobuf/field/fixed32_field.rb +0 -25
  175. data/lib/protobuf/field/fixed64_field.rb +0 -28
  176. data/lib/protobuf/field/float_field.rb +0 -43
  177. data/lib/protobuf/field/int32_field.rb +0 -21
  178. data/lib/protobuf/field/int64_field.rb +0 -34
  179. data/lib/protobuf/field/integer_field.rb +0 -23
  180. data/lib/protobuf/field/message_field.rb +0 -51
  181. data/lib/protobuf/field/sfixed32_field.rb +0 -27
  182. data/lib/protobuf/field/sfixed64_field.rb +0 -28
  183. data/lib/protobuf/field/signed_integer_field.rb +0 -29
  184. data/lib/protobuf/field/sint32_field.rb +0 -21
  185. data/lib/protobuf/field/sint64_field.rb +0 -21
  186. data/lib/protobuf/field/string_field.rb +0 -51
  187. data/lib/protobuf/field/uint32_field.rb +0 -21
  188. data/lib/protobuf/field/uint64_field.rb +0 -21
  189. data/lib/protobuf/field/varint_field.rb +0 -77
  190. data/lib/protobuf/field.rb +0 -74
  191. data/lib/protobuf/generators/base.rb +0 -85
  192. data/lib/protobuf/generators/enum_generator.rb +0 -39
  193. data/lib/protobuf/generators/extension_generator.rb +0 -27
  194. data/lib/protobuf/generators/field_generator.rb +0 -193
  195. data/lib/protobuf/generators/file_generator.rb +0 -262
  196. data/lib/protobuf/generators/group_generator.rb +0 -122
  197. data/lib/protobuf/generators/message_generator.rb +0 -104
  198. data/lib/protobuf/generators/option_generator.rb +0 -17
  199. data/lib/protobuf/generators/printable.rb +0 -160
  200. data/lib/protobuf/generators/service_generator.rb +0 -50
  201. data/lib/protobuf/lifecycle.rb +0 -33
  202. data/lib/protobuf/logging.rb +0 -39
  203. data/lib/protobuf/message/fields.rb +0 -233
  204. data/lib/protobuf/message/serialization.rb +0 -85
  205. data/lib/protobuf/message.rb +0 -241
  206. data/lib/protobuf/optionable.rb +0 -72
  207. data/lib/protobuf/tasks/compile.rake +0 -80
  208. data/lib/protobuf/tasks.rb +0 -1
  209. data/lib/protobuf/varint.rb +0 -20
  210. data/lib/protobuf/varint_pure.rb +0 -31
  211. data/lib/protobuf/version.rb +0 -3
  212. data/lib/protobuf/wire_type.rb +0 -10
  213. data/lib/protobuf.rb +0 -91
  214. data/proto/dynamic_discovery.proto +0 -46
  215. data/proto/google/protobuf/compiler/plugin.proto +0 -183
  216. data/proto/google/protobuf/descriptor.proto +0 -911
  217. data/proto/rpc.proto +0 -71
  218. data/service_executables/.gitkeep +0 -0
  219. data/service_executables/VERSION +0 -1
  220. data/service_executables/linux/contrast-service +0 -0
  221. data/service_executables/mac/contrast-service +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c688788c7666c5ea72351e52ad02fe838923dc0dde589199917d2bfa96080630
4
- data.tar.gz: f63416e47b9b815f0ec7a79858fb11f866bf5c49c952cf278dfb851679f44957
3
+ metadata.gz: 2c32847e196cdcf1540bd39373f9327a46e50cb1c4be6516f2ad5664696c0221
4
+ data.tar.gz: 03b9bc37cf6b8fe3fd0662f120f6f24cc9faf868cf91c7fb698ccbcb52f15aac
5
5
  SHA512:
6
- metadata.gz: 0b5ee56bb30a55609a6252a105c8ab60e0bf66bdcac23e4efa937cfbc99f7669ab5ed7ffdc41dfd1b9659a09a93d2f7714af0eb398b46069542f0dff753c1ccd
7
- data.tar.gz: 84b72b0f516808677745cc1ea7ecdedf762309ceb79eaac2908f1f16ac6abc811f2997bc50673e78101d7845ddd67a73c996c7ed3ebdbca6d33cf88883926499
6
+ metadata.gz: 204a13ebf2cc20d9302d55a1d2201cc0f8f2ba35b5bf1b3392f75c0636f8ab5224de54106af8349c16da111d86f2381e894d8925eccf2df1e46e4d04b99eb7be
7
+ data.tar.gz: ac50424a98754b82bab6576b7205cdb3f6243f5dc6aa9c55f817f15cfba61e1f0858c27a66efd18457442f0b4f2e8ea42cdfcbecdd67c6941edcd86c77b11164
data/.gitignore CHANGED
@@ -21,7 +21,6 @@
21
21
  bin
22
22
  ruby-spec
23
23
  mspec
24
- service_executables
25
24
 
26
25
  # rspec generated files
27
26
  /spec/dummy_files/*
@@ -57,7 +56,6 @@ contrast-agent-*.gem
57
56
 
58
57
  .ruby-version
59
58
  .ruby-gemset
60
- service_executables/*-*
61
59
 
62
60
  # IDE stuff
63
61
  tags
data/.simplecov CHANGED
@@ -4,6 +4,5 @@
4
4
  SimpleCov.minimum_coverage(line: 94)
5
5
  SimpleCov.start do
6
6
  add_filter '/spec/'
7
- add_filter '/lib/protobuf/'
8
7
  enable_coverage :branch
9
8
  end
data/Rakefile CHANGED
@@ -6,7 +6,6 @@ $stdout.sync = true
6
6
  require 'bundler/gem_tasks'
7
7
  require 'rspec/core/rake_task'
8
8
  require 'rake/extensiontask'
9
- load 'protobuf/tasks/compile.rake'
10
9
  require 'fileutils'
11
10
 
12
11
  CLOBBER << 'shared_libraries/*'
@@ -31,15 +31,46 @@ static VALUE contrast_assess_array_join(const int argc, const VALUE *argv,
31
31
  return result;
32
32
  }
33
33
 
34
+ static VALUE contrast_assess_prepend_array_join(const int argc, const VALUE *argv,
35
+ const VALUE ary) {
36
+ VALUE sep, result;
37
+ /* We need to figure out the separator the join method actually used. */
38
+ /* First, check if one was provided. */
39
+ rb_scan_args(argc, argv, "01", &sep);
40
+ /* Second, check to see if `$;` is set*/
41
+ if (NIL_P(sep)) {
42
+ sep = rb_output_fs;
43
+ }
44
+
45
+ /* call the Array.join but patched one */
46
+ result = rb_ary_join(ary, sep);
47
+ /* call the Contrast::Extensions::Assess::ArrayPropagator#cs__track_join */
48
+ result = rb_funcall(array_propagator, rb_sym_assess_track_array_join, 3,
49
+ ary, sep, result);
50
+
51
+ /*call original occurs in ruby*/
52
+ return Qtrue;
53
+ }
54
+
34
55
  void Init_cs__assess_array(void) {
35
- array_propagator =
36
- rb_define_class_under(core_assess, "ArrayPropagator", rb_cObject);
37
- rb_sym_assess_track_array_join = rb_intern("cs__track_join");
38
- /*
39
- * Here we need to check before using the alias or prepend spec
40
- * This patch is happening here, we register the cs__track_join
41
- * method of the Array propagator, and call it here from Ruby.
42
- */
43
- rb_sym_assess_array_join =
44
- contrast_register_patch("Array", "join", contrast_assess_array_join);
56
+
57
+ VALUE rb_mod_ary = rb_const_get(rb_cObject, rb_intern("Array"));
58
+ VALUE rb_sym_ary_join = ID2SYM(rb_intern("join"));
59
+ // check if prepended
60
+ VALUE is_prepended = contrast_check_prepended(rb_mod_ary, rb_sym_ary_join, Qtrue);
61
+ // register the cs__track_join method of the Array propagator, and call it here from Ruby.
62
+ array_propagator = rb_define_class_under(core_assess, "ArrayPropagator", rb_cObject);
63
+ rb_sym_assess_track_array_join = rb_intern("cs__track_join");
64
+
65
+ // register the cs__join method of the ContrastArray for prepending, and call it here from Ruby.
66
+ VALUE contrast_array = rb_define_module_under(core_assess, "ContrastArray");
67
+ rb_define_module_function(contrast_array, "cs__join", contrast_assess_prepend_array_join, -1);
68
+
69
+ if(is_prepended == Qtrue) {
70
+ // do nothing prepend is done in Ruby
71
+ } else {
72
+ // register alias patch
73
+ rb_sym_assess_array_join =
74
+ contrast_register_patch("Array", "join", contrast_assess_array_join);
75
+ }
45
76
  }
@@ -3,8 +3,11 @@
3
3
  static VALUE array_propagator;
4
4
  static VALUE rb_sym_assess_array_join;
5
5
  static VALUE rb_sym_assess_track_array_join;
6
-
6
+ static VALUE rb_mod_ary, rb_sym_ary_join, is_prepended, contrast_array;
7
7
  static VALUE contrast_assess_array_join(const int argc, const VALUE *argv,
8
8
  const VALUE ary);
9
9
 
10
+ static VALUE contrast_assess_prepend_array_join(const int argc, const VALUE *argv,
11
+ const VALUE ary);
12
+
10
13
  void Init_cs__assess_array(void);
@@ -23,7 +23,7 @@ module Contrast
23
23
  # A trigger method is one which can perform a dangerous action, as described by the
24
24
  # Contrast::Agent::Assess::Policy::TriggerNode class. Each such method will call to this module just after
25
25
  # invocation in order to determine if the call was done safely. In those cases where it was not, a Finding
26
- # report is issued to the Service.
26
+ # report is issued to TeamServer.
27
27
  module TriggerMethod
28
28
  extend Contrast::Components::Logger::InstanceMethods
29
29
  extend Contrast::Utils::Assess::TriggerMethodUtils
@@ -105,7 +105,7 @@ module Contrast
105
105
  nil
106
106
  end
107
107
 
108
- # Given a finding, append it to an activity message and send it to the Service for processing. If an
108
+ # Given a finding, append it to an activity message and send it to the TeamServer for processing. If an
109
109
  # activity message does not exist, b/c we're invoked outside of a request context, build an activity and
110
110
  # immediately report it with the finding.
111
111
  #
@@ -7,7 +7,7 @@ module Contrast
7
7
  module Policy
8
8
  module TriggerValidation
9
9
  # Validator used to assert a REDOS finding is actually vulnerable
10
- # before serializing that finding as a DTM to report to the service.
10
+ # before serializing that finding as a DTM to report to the TeamServer.
11
11
  module REDOSValidator
12
12
  RULE_NAME = 'redos'
13
13
 
@@ -7,7 +7,7 @@ module Contrast
7
7
  module Policy
8
8
  module TriggerValidation
9
9
  # Validator used to assert a SSRF finding is actually vulnerable
10
- # before serializing that finding as a DTM to report to the service.
10
+ # before serializing that finding as a DTM to report to the TeamServer.
11
11
  module SSRFValidator
12
12
  RULE_NAME = 'ssrf'
13
13
  URL_PATTERN = %r{(?<protocol>http|https|ftp|sftp|telnet|gopher|rtsp|rtsps|ssh|svn)://(?<host>[^/?]+)(?<path>/?[^?]*)(?<query_string>\?.*)?}i.cs__freeze # rubocop:disable Layout/LineLength
@@ -8,7 +8,7 @@ module Contrast
8
8
  module TriggerValidation
9
9
  # Validator used to assert a Reflected XSS finding is actually
10
10
  # vulnerable before serializing that finding as a DTM to report to
11
- # the service.
11
+ # the TeamServer.
12
12
  module XSSValidator
13
13
  RULE_NAME = 'reflected-xss'
14
14
  SAFE_CONTENT_TYPES = %w[/csv /javascript /json /pdf /x-javascript /x-json].cs__freeze
@@ -1,13 +1,17 @@
1
1
  # Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'contrast/agent/reporting/settings/url_exclusion'
5
+
4
6
  module Contrast
5
7
  module Agent
6
8
  # Given an array of exclusion matcher instances provides methods to
7
9
  # determine if the exclusions apply to particular urls.
8
10
  class Excluder # rubocop:disable Metrics/ClassLength
11
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
9
12
  attr_reader :exclusions
10
13
 
14
+ # @param exclusions [Array<Contrast::Agent::ExclusionMatcher>]
11
15
  def initialize exclusions = []
12
16
  @exclusions = exclusions
13
17
  end
@@ -16,12 +20,12 @@ module Contrast
16
20
  # then we can avoid any tracking for the request.
17
21
  #
18
22
  # @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
19
- # return [Boolean]
23
+ # @return [Boolean]
20
24
  def assess_excluded_by_url? request
21
25
  request_path = request.path
22
26
 
23
- assess_url_exclusions_for_all_rules.any? do |exclusion|
24
- path_match?(exclusion, request_path)
27
+ assess_url_exclusions_for_all_rules.any? do |exclusion_matcher|
28
+ path_match?(exclusion_matcher, request_path)
25
29
  end
26
30
  end
27
31
 
@@ -34,9 +38,9 @@ module Contrast
34
38
  def assess_excluded_by_url_and_rule? request, rule_id
35
39
  request_path = request.path
36
40
 
37
- assess_url_exclusions.any? do |exclusion|
38
- path_match?(exclusion, request_path) &&
39
- (exclusion.assessment_rules.empty? || exclusion.assessment_rules.include?(rule_id))
41
+ assess_url_exclusions.any? do |exclusion_matcher|
42
+ path_match?(exclusion_matcher, request_path) &&
43
+ (exclusion_matcher.assess_rules.empty? || exclusion_matcher.assess_rules.include?(rule_id))
40
44
  end
41
45
  end
42
46
 
@@ -44,13 +48,14 @@ module Contrast
44
48
  # rules, then we can avoid tracking this entry.
45
49
  #
46
50
  # @param request [Contrast::Agent::Request] a wrapper around the Rack::Request for the current request
47
- # @param rule_id [String]
51
+ # @param source_type [String]
52
+ # @param source_name [String]
48
53
  # return [Boolean]
49
54
  def assess_excluded_by_input? request, source_type, source_name
50
55
  request_path = request.path
51
56
 
52
- assess_input_exclusions_for_all_rules.any? do |exclusion|
53
- input_match?(exclusion, source_type, source_name) && path_match?(exclusion, request_path)
57
+ assess_input_exclusions_for_all_rules.any? do |exclusion_matcher|
58
+ input_match?(exclusion_matcher, source_type, source_name) && path_match?(exclusion_matcher, request_path)
54
59
  end
55
60
  end
56
61
 
@@ -66,11 +71,11 @@ module Contrast
66
71
 
67
72
  # We need to check for url exclusions here for the input rules as the url exclusions
68
73
  # that have already been checked didn't include the INPUT exclusions. So we look for
69
- # any INPUT exclusions that apply to the current url and the suppleid rule.
74
+ # any INPUT exclusions that apply to the current url and the supplied rule.
70
75
  path = request.path
71
- rule_input_exclusions = assess_input_exclusions.select do |exclusion|
72
- (exclusion.protection_rules.empty? || exclusion.protection_rules.include?(rule)) && path_match?(exclusion,
73
- path)
76
+ rule_input_exclusions = assess_input_exclusions.select do |exclusion_matcher|
77
+ (exclusion_matcher.protection_rules.empty? || exclusion_matcher.protection_rules.include?(rule)) &&
78
+ path_match?(exclusion_matcher, path)
74
79
  end
75
80
  return false if rule_input_exclusions.empty?
76
81
 
@@ -94,72 +99,85 @@ module Contrast
94
99
  def protect_excluded_by_url? request
95
100
  request_path = request.path
96
101
 
97
- protect_url_exclusions_for_all_rules.any? do |exclusion|
98
- path_match?(exclusion, request_path)
102
+ protect_url_exclusions_for_all_rules.any? do |exclusion_matcher|
103
+ path_match?(exclusion_matcher, request_path)
99
104
  end
100
105
  end
101
106
 
102
107
  private
103
108
 
109
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
104
110
  def assess_url_exclusions_for_all_rules
105
- @_assess_url_exclusions_for_all_rules ||= assess_url_exclusions.select do |exclusion|
106
- exclusion.assessment_rules.empty?
111
+ @_assess_url_exclusions_for_all_rules ||= assess_url_exclusions.select do |exclusion_matcher|
112
+ exclusion_matcher.assess_rules.empty?
107
113
  end
108
114
  end
109
115
 
116
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
110
117
  def assess_url_exclusions
111
- @_assess_url_exclusions ||= assess_exclusions.select do |exclusion|
112
- exclusion.type == Contrast::Api::Settings::Exclusion::ExclusionType::URL
118
+ @_assess_url_exclusions ||= assess_exclusions.select do |exclusion_matcher|
119
+ exclusion_matcher.type == :URL
113
120
  end
114
121
  end
115
122
 
123
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
116
124
  def assess_input_exclusions_for_all_rules
117
- @_assess_input_exclusions_for_all_rules ||= assess_input_exclusions.select do |exclusion|
118
- exclusion.assessment_rules.empty?
125
+ @_assess_input_exclusions_for_all_rules ||= assess_input_exclusions.select do |exclusion_matcher|
126
+ exclusion_matcher.assess_rules.empty?
119
127
  end
120
128
  end
121
129
 
130
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
122
131
  def assess_input_exclusions
123
- @_assess_input_exclusions ||= assess_exclusions.select do |exclusion|
124
- exclusion.type == Contrast::Api::Settings::Exclusion::ExclusionType::INPUT
132
+ @_assess_input_exclusions ||= assess_exclusions.select do |exclusion_matcher|
133
+ exclusion_matcher.type == :INPUT
125
134
  end
126
135
  end
127
136
 
137
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
128
138
  def assess_exclusions
129
139
  @_assess_exclusions ||= @exclusions.select(&:assess)
130
140
  end
131
141
 
142
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
132
143
  def protect_url_exclusions_for_all_rules
133
- @_protect_url_exclusions_for_all_rules ||= protect_url_exclusions.select do |exclusion|
134
- exclusion.protection_rules.empty?
144
+ @_protect_url_exclusions_for_all_rules ||= protect_url_exclusions.select do |exclusion_matcher|
145
+ exclusion_matcher.protect_rules.empty?
135
146
  end
136
147
  end
137
148
 
149
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
138
150
  def protect_url_exclusions
139
- @_protect_url_exclusions ||= protect_exclusions.select do |exclusion|
140
- exclusion.type == Contrast::Api::Settings::Exclusion::ExclusionType::URL
151
+ @_protect_url_exclusions ||= protect_exclusions.select do |exclusion_matcher|
152
+ exclusion_matcher.type == :URL
141
153
  end
142
154
  end
143
155
 
156
+ # @return [Array<Contrast::Agent::ExclusionMatcher>]
144
157
  def protect_exclusions
145
158
  @_protect_exclusions ||= @exclusions.select(&:protect)
146
159
  end
147
160
 
148
- def path_match? exclusion, path
149
- exclusion.wildcard_url || exclusion.urls.any? { |url| url.match?(path) }
161
+ # @return [Boolean]
162
+ def path_match? exclusion_matcher, path
163
+ exclusion_matcher.wildcard_url || exclusion_matcher.urls.any? { |url| url.match?(path) }
150
164
  end
151
165
 
166
+ # @param exclusion [Contrast::Agent::ExclusionMatcher]
167
+ # @param source_type [String]
168
+ # @param source_name [String]
169
+ # @return [Boolean]
152
170
  def input_match? exclusion, source_type, source_name
153
171
  case exclusion.input_type
154
- when Contrast::Api::Settings::Exclusion::InputType::PARAMETER
172
+ when 'PARAMETER'
155
173
  input_match_parameter?(exclusion, source_type, source_name)
156
- when Contrast::Api::Settings::Exclusion::InputType::COOKIE
174
+ when 'COOKIE'
157
175
  input_match_cookie?(exclusion, source_type, source_name)
158
- when Contrast::Api::Settings::Exclusion::InputType::HEADER
176
+ when 'HEADER'
159
177
  input_match_header?(exclusion, source_type, source_name)
160
- when Contrast::Api::Settings::Exclusion::InputType::BODY
178
+ when 'BODY'
161
179
  Contrast::Agent::Assess::Policy::SourceMethod::BODY_TYPE == source_type
162
- when Contrast::Api::Settings::Exclusion::InputType::QUERYSTRING
180
+ when 'QUERYSTRING'
163
181
  Contrast::Agent::Assess::Policy::SourceMethod::QUERYSTRING_TYPE == source_type
164
182
  else
165
183
  false
@@ -2,6 +2,10 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require 'contrast/components/logger'
5
+ require 'contrast/agent/reporting/settings/exclusion_base'
6
+ require 'contrast/agent/reporting/settings/code_exclusion'
7
+ require 'contrast/agent/reporting/settings/input_exclusion'
8
+ require 'contrast/agent/reporting/settings/url_exclusion'
5
9
 
6
10
  module Contrast
7
11
  module Agent
@@ -13,22 +17,30 @@ module Contrast
13
17
 
14
18
  extend Forwardable
15
19
 
16
- attr_reader :protect, :assess, :urls, :wildcard_url, :wildcard_input
20
+ attr_reader :protect, :assess, :type, :urls, :wildcard_url, :wildcard_input
17
21
 
18
- def_delegators :@exclusion, :type, :assessment_rules, :protection_rules, :input_type, :input_name
22
+ def_delegators :@exclusion, :protect_rules, :assess_rules, :input_type, :input_name
19
23
 
20
24
  # Create a matcher around an exclusion sent from TeamServer.
21
25
  #
22
- # @param excl [Contrast::Api::Settings::Exclusion]
26
+ # @param excl [Contrast::Agent::Reporting::Settings::ExclusionBase]
23
27
  # @return [Contrast::Agent::ExclusionMatcher]
24
28
  def initialize excl
25
29
  @exclusion = excl
26
30
  @protect = @exclusion.protect
27
31
  @assess = @exclusion.assess
28
32
 
29
- handle_wildcard_input
30
- handle_wildcard_url
31
- handle_wildcard_code
33
+ case excl
34
+ when Contrast::Agent::Reporting::Settings::CodeExclusion
35
+ handle_wildcard_code
36
+ @type = :CODE
37
+ when Contrast::Agent::Reporting::Settings::InputExclusion
38
+ handle_wildcard_input
39
+ @type = :INPUT
40
+ when Contrast::Agent::Reporting::Settings::UrlExclusion
41
+ handle_wildcard_url
42
+ @type = :URL
43
+ end
32
44
  end
33
45
 
34
46
  # According to the docs for exclusions, user input applies to all inputs if
@@ -97,7 +109,7 @@ module Contrast
97
109
  end
98
110
 
99
111
  def code?
100
- @exclusion.type == Contrast::Api::Settings::Exclusion::ExclusionType::CODE
112
+ @type == :CODE
101
113
  end
102
114
 
103
115
  def match_all?
@@ -105,12 +117,12 @@ module Contrast
105
117
  end
106
118
 
107
119
  # Determine if the given rule is excluded by this exclusion.
108
- # In this case, the `protection_rules` being empty means apply to all rules,
120
+ # In this case, the `protect_rules` being empty means apply to all rules,
109
121
  # not no rules
110
122
  #
111
123
  # @param rule - the id of the rule which we're checking for exclusion
112
124
  def protection_rule? rule
113
- protect? && (@exclusion.protection_rules.empty? || @exclusion.protection_rules.include?(rule))
125
+ protect? && (@exclusion.protect_rules.empty? || @exclusion.protect_rules.include?(rule))
114
126
  end
115
127
 
116
128
  # Determine if the given rule is excluded by this exclusion.
@@ -73,12 +73,12 @@ module Contrast
73
73
  private
74
74
 
75
75
  # Startup the Agent as part of the initialization process:
76
- # - start the service sending thread, responsible for sending and processing messages
77
- # - start the heartbeat thread, which triggers service startup
76
+ # - start the TeamServer sending thread, responsible for sending and processing messages
77
+ # - start the heartbeat thread, which handles periodic messages to TeamServer
78
78
  # - start instrumenting libraries and do a 'catchup' patch for everything we didn't see get loaded
79
79
  # - enable TracePoint, which handles all class loads and required instrumentation going forward
80
80
  def agent_startup_routine
81
- logger.debug_with_time('middleware: starting service') do
81
+ logger.debug_with_time('middleware: starting reporting threads') do
82
82
  Contrast::Agent.thread_watcher.ensure_running?
83
83
  end
84
84
 
@@ -147,7 +147,7 @@ module Contrast
147
147
  # which is being triggered when there is a failure within the pre-call with the agent
148
148
  def pre_call_with_agent context, request_handler
149
149
  with_contrast_scope do
150
- context.service_extract_request
150
+ context.protect_input_analysis
151
151
  request_handler.ruleset.prefilter
152
152
  end
153
153
  rescue StandardError => e
@@ -56,6 +56,7 @@ module Contrast
56
56
  unless Contrast::Agent::Assess.cs__object_method_prepended?(Marshal, :load, false)
57
57
  apply_marshal_load_alias_patch
58
58
  end
59
+ apply_array_join_prepend_patch if Contrast::Agent::Assess.cs__object_method_prepended?(Array, :join, true)
59
60
  true
60
61
  end
61
62
  end
@@ -121,6 +122,11 @@ module Contrast
121
122
  Marshal.alias_method(:cs__marshal_load, :load)
122
123
  Marshal.alias_method(:load, :cs__marshal_load)
123
124
  end
125
+
126
+ # Prepend Contrast::Extension::Assess::ContrastArray to pick up the ContrastArray#join method
127
+ def apply_array_join_prepend_patch
128
+ Array.prepend(Contrast::Extension::Assess::ContrastArray)
129
+ end
124
130
  end
125
131
  end
126
132
  end