contrast-agent 7.2.0 → 7.3.1

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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/lib/contrast/agent/assess/policy/policy_node.rb +25 -6
  3. data/lib/contrast/agent/assess/policy/propagator/response.rb +64 -0
  4. data/lib/contrast/agent/assess/policy/propagator.rb +1 -0
  5. data/lib/contrast/agent/assess/policy/source_method.rb +5 -0
  6. data/lib/contrast/agent/assess/rule/response/body_rule.rb +22 -7
  7. data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +4 -1
  8. data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +62 -23
  9. data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +37 -4
  10. data/lib/contrast/agent/protect/rule/base.rb +5 -1
  11. data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +27 -11
  12. data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +0 -1
  13. data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +2 -2
  14. data/lib/contrast/agent/protect/rule/input_classification/base.rb +191 -0
  15. data/lib/contrast/agent/protect/rule/input_classification/base64_statistic.rb +71 -0
  16. data/lib/contrast/agent/protect/rule/input_classification/cached_result.rb +37 -0
  17. data/lib/contrast/agent/protect/rule/input_classification/encoding.rb +109 -0
  18. data/lib/contrast/agent/protect/rule/input_classification/encoding_rates.rb +47 -0
  19. data/lib/contrast/agent/protect/rule/input_classification/extendable.rb +80 -0
  20. data/lib/contrast/agent/protect/rule/input_classification/lru_cache.rb +198 -0
  21. data/lib/contrast/agent/protect/rule/input_classification/match_rates.rb +66 -0
  22. data/lib/contrast/agent/protect/rule/input_classification/rates.rb +53 -0
  23. data/lib/contrast/agent/protect/rule/input_classification/statistics.rb +115 -0
  24. data/lib/contrast/agent/protect/rule/input_classification/utils.rb +23 -0
  25. data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +17 -7
  26. data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_input_classification.rb +18 -15
  27. data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +2 -2
  28. data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +18 -15
  29. data/lib/contrast/agent/protect/rule/xss/reflected_xss_input_classification.rb +19 -17
  30. data/lib/contrast/agent/reporting/attack_result/attack_result.rb +6 -0
  31. data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +2 -7
  32. data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +11 -0
  33. data/lib/contrast/agent/reporting/input_analysis/input_type.rb +33 -1
  34. data/lib/contrast/agent/reporting/masker/masker_utils.rb +1 -1
  35. data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +1 -0
  36. data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +1 -0
  37. data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -1
  38. data/lib/contrast/agent/telemetry/base.rb +28 -2
  39. data/lib/contrast/agent/telemetry/base64_hash.rb +55 -0
  40. data/lib/contrast/agent/telemetry/cache_hash.rb +55 -0
  41. data/lib/contrast/agent/telemetry/client.rb +10 -2
  42. data/lib/contrast/agent/telemetry/exception/obfuscate.rb +4 -3
  43. data/lib/contrast/agent/telemetry/{hash.rb → exception_hash.rb} +1 -1
  44. data/lib/contrast/agent/telemetry/identifier.rb +13 -26
  45. data/lib/contrast/agent/telemetry/input_analysis_cache_event.rb +27 -0
  46. data/lib/contrast/agent/telemetry/input_analysis_encoding_event.rb +26 -0
  47. data/lib/contrast/agent/telemetry/input_analysis_event.rb +91 -0
  48. data/lib/contrast/agent/telemetry/metric_event.rb +12 -0
  49. data/lib/contrast/agent/telemetry/startup_metrics_event.rb +0 -8
  50. data/lib/contrast/agent/version.rb +1 -1
  51. data/lib/contrast/components/assess.rb +33 -6
  52. data/lib/contrast/components/base.rb +4 -2
  53. data/lib/contrast/components/config.rb +6 -6
  54. data/lib/contrast/components/protect.rb +11 -1
  55. data/lib/contrast/components/sampling.rb +15 -10
  56. data/lib/contrast/config/diagnostics/command_line.rb +2 -2
  57. data/lib/contrast/config/diagnostics/environment_variables.rb +5 -2
  58. data/lib/contrast/config/diagnostics/tools.rb +15 -5
  59. data/lib/contrast/config/yaml_file.rb +8 -0
  60. data/lib/contrast/configuration.rb +61 -29
  61. data/lib/contrast/framework/rails/support.rb +3 -0
  62. data/lib/contrast/logger/application.rb +3 -3
  63. data/lib/contrast/utils/assess/event_limit_utils.rb +13 -13
  64. data/lib/contrast/utils/assess/propagation_method_utils.rb +2 -0
  65. data/lib/contrast/utils/metrics_hash.rb +1 -1
  66. data/lib/contrast/utils/object_share.rb +2 -1
  67. data/lib/contrast/utils/os.rb +1 -9
  68. data/lib/contrast/utils/response_utils.rb +12 -0
  69. data/lib/contrast/utils/timer.rb +2 -0
  70. data/lib/contrast.rb +9 -2
  71. data/resources/assess/policy.json +80 -3
  72. data/ruby-agent.gemspec +1 -1
  73. metadata +22 -6
  74. data/lib/contrast/utils/input_classification_base.rb +0 -169
@@ -70,13 +70,13 @@ module Contrast
70
70
  if current_count == event_max
71
71
  return if event_limit_counts.key?(get_event_limit_key(method_policy, context))
72
72
 
73
- logger.warn('Event Limit Reached:',
74
- {
75
- count: current_count,
76
- max: event_max,
77
- policy: method_policy.method_name,
78
- node: method_policy
79
- })
73
+ logger.debug('Event Limit Reached:',
74
+ {
75
+ count: current_count,
76
+ max: event_max,
77
+ policy: method_policy.method_name,
78
+ node: method_policy
79
+ })
80
80
  # increment to be over count for logging purposes
81
81
  increment_event_count(method_policy)
82
82
  increment_event_limit_logs(method_policy, context)
@@ -87,12 +87,12 @@ module Contrast
87
87
  return if event_limit_counts.key?(get_event_limit_key(method_policy, context))
88
88
 
89
89
  # increment to be over count for logging purposes
90
- logger.warn('Event Limit Exceeded:',
91
- {
92
- count: current_count,
93
- policy: method_policy.method_name,
94
- node: method_policy
95
- })
90
+ logger.debug('Event Limit Exceeded:',
91
+ {
92
+ count: current_count,
93
+ policy: method_policy.method_name,
94
+ node: method_policy
95
+ })
96
96
  increment_event_limit_logs(method_policy, context)
97
97
  return true
98
98
  end
@@ -18,6 +18,7 @@ module Contrast
18
18
  REPLACE_ACTION = 'REPLACE'
19
19
  REMOVE_ACTION = 'REMOVE'
20
20
  REVERSE_ACTION = 'REVERSE'
21
+ RESPONSE_ACTION = 'RESPONSE'
21
22
  SPLAT_ACTION = 'SPLAT'
22
23
  SPLIT_ACTION = 'SPLIT'
23
24
  DB_WRITE_ACTION = 'DB_WRITE'
@@ -37,6 +38,7 @@ module Contrast
37
38
  REPLACE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Replace,
38
39
  REMOVE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Remove,
39
40
  REVERSE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Reverse,
41
+ RESPONSE_ACTION => Contrast::Agent::Assess::Policy::Propagator::Response,
40
42
  SPLAT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Splat,
41
43
  SPLIT_ACTION => Contrast::Agent::Assess::Policy::Propagator::Split
42
44
  }.cs__freeze
@@ -17,7 +17,7 @@ module Contrast
17
17
  'The key extends the allowed length.',
18
18
  'The provided value is not the right data type'
19
19
  ].cs__freeze
20
- KEY_REGEXP = /[a-zA-Z0-9_-]{1,63}/.cs__freeze
20
+ KEY_REGEXP = /[a-zA-Z0-9._-]{1,63}/.cs__freeze
21
21
 
22
22
  def initialize data_type, *several_variants
23
23
  super
@@ -38,7 +38,8 @@ module Contrast
38
38
  AT = '@'
39
39
  LEFT_ANGLE = '<'
40
40
  COLON_SLASH_SLASH = '://'
41
- DOLLAR_SIGN = '$'
41
+ DOLLAR_SIGN = '$'
42
+ AMPERSAND = '&'
42
43
  CARROT = '^'
43
44
  BANG = '!'
44
45
 
@@ -8,7 +8,7 @@ module Contrast
8
8
  module Utils
9
9
  # Simple utility used to make OS calls and determine state. For that state
10
10
  # which will not change at runtime, such as the operating system, the
11
- # Utility memozies to avoid multiple lookups.
11
+ # Utility memoizes to avoid multiple lookups.
12
12
  module OS
13
13
  extend Contrast::Components::Scope::InstanceMethods
14
14
 
@@ -25,14 +25,6 @@ module Contrast
25
25
  @_mac = RUBY_PLATFORM.include?('darwin') if @_mac.nil?
26
26
  @_mac
27
27
  end
28
-
29
- def unix?
30
- !windows?
31
- end
32
-
33
- def linux?
34
- (unix? and !mac?)
35
- end
36
28
  end
37
29
  end
38
30
  end
@@ -19,6 +19,7 @@ module Contrast
19
19
  def extract_body body
20
20
  return unless body
21
21
  return if body_is_file?(body)
22
+ return if body_is_sprockets?(body)
22
23
 
23
24
  return handle_rack_body_proxy(body) if body.is_a?(Rack::BodyProxy)
24
25
  return extract_body(body.body) if sub_extractable?(body)
@@ -74,6 +75,17 @@ module Contrast
74
75
 
75
76
  false
76
77
  end
78
+
79
+ # Detects Rails' Sprockets asset pipeline objects passed as body.
80
+ # Returns false if Sprockets is passed as body, the Agent does not
81
+ # support Sprockets::Asset for body extraction.
82
+ #
83
+ # @param body [String, Rack::File, Rack::BodyProxy]
84
+ def body_is_sprockets? body
85
+ return body.cs__is_a?(Sprockets::Asset) if defined?(Sprockets) && defined?(Sprockets::Asset)
86
+
87
+ false
88
+ end
77
89
  end
78
90
  end
79
91
  end
@@ -1,6 +1,8 @@
1
1
  # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
2
  # frozen_string_literal: true
3
3
 
4
+ require 'time'
5
+
4
6
  module Contrast
5
7
  module Utils
6
8
  # Timer is class that can track state about when an event starts and how long it takes
data/lib/contrast.rb CHANGED
@@ -61,10 +61,12 @@ require 'contrast/components/sampling'
61
61
  require 'contrast/components/scope'
62
62
  require 'contrast/components/settings'
63
63
  require 'contrast/utils/routes_sent'
64
- require 'contrast/agent/telemetry/hash'
64
+ require 'contrast/agent/telemetry/exception_hash'
65
65
  require 'contrast/agent/telemetry/telemetry'
66
66
  require 'contrast/agent/telemetry/exception/event'
67
67
  require 'contrast/agent_lib/interface'
68
+ require 'contrast/agent/telemetry/cache_hash'
69
+ require 'contrast/agent/telemetry/base64_hash'
68
70
 
69
71
  module Contrast # :nodoc:
70
72
  CONFIG = Contrast::Components::Config::Interface.new
@@ -82,7 +84,12 @@ module Contrast # :nodoc:
82
84
  end
83
85
 
84
86
  module Contrast
85
- TELEMETRY_EXCEPTIONS = (Contrast::Agent::Telemetry::Hash.new if Contrast::Agent::Telemetry.exceptions_enabled?)
87
+ TELEMETRY_EXCEPTIONS = (if Contrast::Agent::Telemetry.exceptions_enabled?
88
+ Contrast::Agent::Telemetry::ExceptionHash.new
89
+ end)
90
+ TELEMETRY_IA_CACHE = (Contrast::Agent::Telemetry::CacheHash.new if Contrast::Agent::Telemetry::Base.enabled?)
91
+ TELEMETRY_BASE64_HASH = (Contrast::Agent::Telemetry::Base64Hash.new if Contrast::Agent::Telemetry::Base.enabled? &&
92
+ Contrast::PROTECT.normalize_base64?)
86
93
  ROUTES_SENT = Contrast::Utils::RoutesSent.new
87
94
  end
88
95
 
@@ -8,7 +8,35 @@
8
8
  "target":"R",
9
9
  "type":"PARAMETER",
10
10
  "tags":["CROSS_SITE"]
11
- }, {
11
+ },
12
+ {
13
+ "class_name":"Net::HTTPResponse",
14
+ "instance_method": true,
15
+ "method_visibility": "public",
16
+ "method_name":"body",
17
+ "target":"R",
18
+ "type":"BODY",
19
+ "tags":["CROSS_SITE"]
20
+ },
21
+ {
22
+ "class_name":"Rack::Response",
23
+ "instance_method": true,
24
+ "method_visibility": "public",
25
+ "method_name":"body",
26
+ "target":"R",
27
+ "type":"BODY",
28
+ "tags":["CROSS_SITE"]
29
+ },
30
+ {
31
+ "class_name":"Sinatra::Response",
32
+ "instance_method": true,
33
+ "method_visibility": "public",
34
+ "method_name":"body",
35
+ "target":"R",
36
+ "type":"BODY",
37
+ "tags":["CROSS_SITE"]
38
+ },
39
+ {
12
40
  "class_name":"Rack::Request::Helpers",
13
41
  "instance_method": true,
14
42
  "method_visibility": "public",
@@ -990,7 +1018,35 @@
990
1018
  "source": "P0",
991
1019
  "target": "R",
992
1020
  "action": "SPLAT"
993
- }, {
1021
+ },
1022
+ {
1023
+ "class_name": "ActiveSupport::JSON",
1024
+ "method_name": "encode",
1025
+ "instance_method": false,
1026
+ "method_visibility": "public",
1027
+ "source": "P0",
1028
+ "target": "R",
1029
+ "action": "SPLAT"
1030
+ },
1031
+ {
1032
+ "class_name": "JSON",
1033
+ "method_name": "generate",
1034
+ "instance_method": false,
1035
+ "method_visibility": "public",
1036
+ "source": "P0",
1037
+ "target": "R",
1038
+ "action": "SPLAT"
1039
+ },
1040
+ {
1041
+ "class_name": "JSON",
1042
+ "method_name": "pretty_generate",
1043
+ "instance_method": false,
1044
+ "method_visibility": "public",
1045
+ "source": "P0",
1046
+ "target": "R",
1047
+ "action": "SPLAT"
1048
+ },
1049
+ {
994
1050
  "class_name": "Zlib::Deflate",
995
1051
  "method_name": "deflate",
996
1052
  "instance_method": false,
@@ -1082,7 +1138,28 @@
1082
1138
  "source": "P0",
1083
1139
  "target": "R",
1084
1140
  "action": "SPLAT"
1085
- }, {
1141
+ },
1142
+ {
1143
+ "class_name":"Net::HTTPRequest",
1144
+ "instance_method": true,
1145
+ "method_visibility": "public",
1146
+ "method_name":"body=",
1147
+ "source":"P0",
1148
+ "target":"O",
1149
+ "action":"KEEP"
1150
+ },
1151
+ {
1152
+ "class_name":"Net::HTTP",
1153
+ "instance_method": true,
1154
+ "method_visibility": "public",
1155
+ "method_name":"request",
1156
+ "action": "CUSTOM",
1157
+ "patch_class": "Contrast::Agent::Assess::Policy::Propagator::Response",
1158
+ "patch_method": "net_response_keep",
1159
+ "source": "O,P1",
1160
+ "target": "R"
1161
+ },
1162
+ {
1086
1163
  "class_name": "URI::Generic",
1087
1164
  "method_name": "initialize",
1088
1165
  "instance_method": true,
data/ruby-agent.gemspec CHANGED
@@ -121,7 +121,7 @@ def self.add_dependencies spec
121
121
  spec.add_dependency 'rack', '~> 2.0'
122
122
 
123
123
  # bind this directly as we've had issues w/ build changes on bug release
124
- spec.add_dependency 'contrast-agent-lib', '1.1.0'
124
+ spec.add_dependency 'contrast-agent-lib', '1.1.1'
125
125
  end
126
126
 
127
127
  # Enumerate the files required to build the Agent.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: contrast-agent
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0
4
+ version: 7.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - galen.palmer@contrastsecurity.com
@@ -13,7 +13,7 @@ authors:
13
13
  autorequire:
14
14
  bindir: exe
15
15
  cert_chain: []
16
- date: 2023-05-31 00:00:00.000000000 Z
16
+ date: 2023-08-04 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: bundler
@@ -669,14 +669,14 @@ dependencies:
669
669
  requirements:
670
670
  - - '='
671
671
  - !ruby/object:Gem::Version
672
- version: 1.1.0
672
+ version: 1.1.1
673
673
  type: :runtime
674
674
  prerelease: false
675
675
  version_requirements: !ruby/object:Gem::Requirement
676
676
  requirements:
677
677
  - - '='
678
678
  - !ruby/object:Gem::Version
679
- version: 1.1.0
679
+ version: 1.1.1
680
680
  description: This gem instantiates a Rack middleware for rack-based web applications
681
681
  in order to provide Interactive Application Security Testing and Protection.
682
682
  email:
@@ -930,6 +930,7 @@ files:
930
930
  - lib/contrast/agent/assess/policy/propagator/rack_protection.rb
931
931
  - lib/contrast/agent/assess/policy/propagator/remove.rb
932
932
  - lib/contrast/agent/assess/policy/propagator/replace.rb
933
+ - lib/contrast/agent/assess/policy/propagator/response.rb
933
934
  - lib/contrast/agent/assess/policy/propagator/reverse.rb
934
935
  - lib/contrast/agent/assess/policy/propagator/select.rb
935
936
  - lib/contrast/agent/assess/policy/propagator/splat.rb
@@ -1023,6 +1024,17 @@ files:
1023
1024
  - lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb
1024
1025
  - lib/contrast/agent/protect/rule/default_scanner.rb
1025
1026
  - lib/contrast/agent/protect/rule/deserialization/deserialization.rb
1027
+ - lib/contrast/agent/protect/rule/input_classification/base.rb
1028
+ - lib/contrast/agent/protect/rule/input_classification/base64_statistic.rb
1029
+ - lib/contrast/agent/protect/rule/input_classification/cached_result.rb
1030
+ - lib/contrast/agent/protect/rule/input_classification/encoding.rb
1031
+ - lib/contrast/agent/protect/rule/input_classification/encoding_rates.rb
1032
+ - lib/contrast/agent/protect/rule/input_classification/extendable.rb
1033
+ - lib/contrast/agent/protect/rule/input_classification/lru_cache.rb
1034
+ - lib/contrast/agent/protect/rule/input_classification/match_rates.rb
1035
+ - lib/contrast/agent/protect/rule/input_classification/rates.rb
1036
+ - lib/contrast/agent/protect/rule/input_classification/statistics.rb
1037
+ - lib/contrast/agent/protect/rule/input_classification/utils.rb
1026
1038
  - lib/contrast/agent/protect/rule/no_sqli/mongo_no_sql_scanner.rb
1027
1039
  - lib/contrast/agent/protect/rule/no_sqli/no_sqli.rb
1028
1040
  - lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb
@@ -1176,6 +1188,8 @@ files:
1176
1188
  - lib/contrast/agent/response/response.rb
1177
1189
  - lib/contrast/agent/scope/scope.rb
1178
1190
  - lib/contrast/agent/telemetry/base.rb
1191
+ - lib/contrast/agent/telemetry/base64_hash.rb
1192
+ - lib/contrast/agent/telemetry/cache_hash.rb
1179
1193
  - lib/contrast/agent/telemetry/client.rb
1180
1194
  - lib/contrast/agent/telemetry/event.rb
1181
1195
  - lib/contrast/agent/telemetry/exception.rb
@@ -1185,8 +1199,11 @@ files:
1185
1199
  - lib/contrast/agent/telemetry/exception/message_exception.rb
1186
1200
  - lib/contrast/agent/telemetry/exception/obfuscate.rb
1187
1201
  - lib/contrast/agent/telemetry/exception/stack_frame.rb
1188
- - lib/contrast/agent/telemetry/hash.rb
1202
+ - lib/contrast/agent/telemetry/exception_hash.rb
1189
1203
  - lib/contrast/agent/telemetry/identifier.rb
1204
+ - lib/contrast/agent/telemetry/input_analysis_cache_event.rb
1205
+ - lib/contrast/agent/telemetry/input_analysis_encoding_event.rb
1206
+ - lib/contrast/agent/telemetry/input_analysis_event.rb
1190
1207
  - lib/contrast/agent/telemetry/metric_event.rb
1191
1208
  - lib/contrast/agent/telemetry/startup_metrics_event.rb
1192
1209
  - lib/contrast/agent/telemetry/telemetry.rb
@@ -1310,7 +1327,6 @@ files:
1310
1327
  - lib/contrast/utils/hash_utils.rb
1311
1328
  - lib/contrast/utils/head_dump_utils_extend.rb
1312
1329
  - lib/contrast/utils/heap_dump_util.rb
1313
- - lib/contrast/utils/input_classification_base.rb
1314
1330
  - lib/contrast/utils/invalid_configuration_util.rb
1315
1331
  - lib/contrast/utils/io_util.rb
1316
1332
  - lib/contrast/utils/job_servers_running.rb
@@ -1,169 +0,0 @@
1
- # Copyright (c) 2023 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
2
- # frozen_string_literal: true
3
-
4
- require 'contrast/utils/object_share'
5
- require 'contrast/agent/reporting/input_analysis/input_type'
6
- require 'contrast/agent/reporting/input_analysis/score_level'
7
- require 'contrast/agent/protect/input_analyzer/input_analyzer'
8
- require 'contrast/components/logger'
9
-
10
- module Contrast
11
- module Agent
12
- module Protect
13
- module Rule
14
- # This module will include all the similar information for all input classifications
15
- # between different rules
16
- module InputClassificationBase
17
- UNKNOWN_KEY = 'unknown'
18
- THRESHOLD = 90.cs__freeze
19
- WORTHWATCHING_THRESHOLD = 10.cs__freeze
20
- include Contrast::Agent::Reporting::InputType
21
- include Contrast::Agent::Reporting::ScoreLevel
22
- include Contrast::Components::Logger::InstanceMethods
23
-
24
- KEYS_NEEDED = [COOKIE_VALUE, PARAMETER_VALUE, JSON_VALUE, MULTIPART_VALUE, XML_VALUE, DWR_VALUE].cs__freeze
25
-
26
- # Input Classification stage is done to determine if an user input is
27
- # DEFINITEATTACK or to be ignored.
28
- #
29
- # @param rule_id [String] Name of the protect rule.
30
- # @param input_type [Symbol, Contrast::Agent::Reporting::InputType] The type of the user input.
31
- # @param value [String, Array<String>] the value of the input.
32
- # @param input_analysis [Contrast::Agent::Reporting::InputAnalysis] Holds all the results from the
33
- # agent analysis from the current
34
- # Request.
35
- # @return ia [Contrast::Agent::Reporting::InputAnalysis, nil] with updated results.
36
- def classify rule_id, input_type, value, input_analysis
37
- return unless (rule = Contrast::PROTECT.rule(rule_id))
38
- return unless rule.applicable_user_inputs.include?(input_type)
39
- return unless input_analysis.request
40
-
41
- Array(value).each do |val|
42
- Array(val).each do |v|
43
- next unless v
44
-
45
- result = create_new_input_result(input_analysis.request, rule.rule_name, input_type, v)
46
- append_result(input_analysis, result)
47
- end
48
- end
49
-
50
- input_analysis
51
- rescue StandardError => e
52
- logger.debug("An Error was recorded in the input classification of the #{ rule_id }")
53
- logger.debug(e)
54
- nil
55
- end
56
-
57
- # Creates new isntance of InputAnalysisResult with basic info.
58
- #
59
- # @param rule_id [String] The name of the Protect Rule.
60
- # @param input_type [Contrast::Agent::Reporting::InputType] The type of the user input.
61
- # @param value [String, Array<String>] the value of the input.
62
- # @param path [String] the path of the current request context.
63
- #
64
- # @return res [Contrast::Agent::Reporting::InputAnalysisResult]
65
- def new_ia_result rule_id, input_type, path, value = nil
66
- res = Contrast::Agent::Reporting::InputAnalysisResult.new
67
- res.rule_id = rule_id
68
- res.input_type = input_type
69
- res.path = path
70
- res.value = value
71
- res
72
- end
73
-
74
- # This methods checks if input is value that matches a key in the input.
75
- #
76
- # @param request [Contrast::Agent::Request] the current request context.
77
- # @param result [Contrast::Agent::Reporting::InputAnalysisResult] result to be updated.
78
- # @param input_type [Contrast::Agent::Reporting::InputType] The type of the user input.
79
- # @param value [String, Array<String>] the value of the input.
80
- #
81
- # @return result [Contrast::Agent::Reporting::InputAnalysisResult] updated with key result.
82
- def add_needed_key request, result, input_type, value
83
- case input_type
84
- when COOKIE_VALUE
85
- result.key = request.cookies.key(value)
86
- when PARAMETER_VALUE, URL_PARAMETER
87
- result.key = request.parameters.key(value)
88
- when HEADER
89
- result.key = request.headers.key(value)
90
- when UNKNOWN
91
- result.key = UNKNOWN_KEY
92
- else
93
- result.key
94
- end
95
- rescue StandardError => e
96
- logger.warn('Could not find proper key for input traced value', message: e)
97
- end
98
-
99
- # Some input types are not yet supported from the AgentLib.
100
- # This will convert the type to the closet possible if viable,
101
- # so that the input tracing could be done.
102
- #
103
- # @param input_type [Contrast::Agent::Reporting::InputType] The type of the user input.
104
- # @return [Integer<Contrast::AgentLib::Interface::INPUT_SET>]
105
- def convert_input_type input_type
106
- case input_type
107
- when URI, URL_PARAMETER
108
- Contrast::AGENT_LIB.input_set[:URI_PATH]
109
- when BODY, DWR_VALUE, SOCKET, UNDEFINED_TYPE, UNKNOWN, REQUEST, QUERYSTRING
110
- Contrast::AGENT_LIB.input_set[:PARAMETER_VALUE]
111
- when HEADER
112
- Contrast::AGENT_LIB.input_set[:HEADER_VALUE]
113
- when MULTIPART_VALUE, MULTIPART_FIELD_NAME
114
- Contrast::AGENT_LIB.input_set[:MULTIPART_NAME]
115
- when JSON_ARRAYED_VALUE
116
- Contrast::AGENT_LIB.input_set[:JSON_KEY]
117
- when PARAMETER_NAME
118
- Contrast::AGENT_LIB.input_set[:PARAMETER_KEY]
119
- else
120
- Contrast::AGENT_LIB.input_set[input_type]
121
- end
122
- rescue StandardError => e
123
- logger.debug('Protect Input classification could not determine input type, falling back to default',
124
- error: e)
125
- Contrast::AGENT_LIB.input_set[:PARAMETER_VALUE]
126
- end
127
-
128
- private
129
-
130
- # This methods checks if input is tagged WORTHWATCHING or IGNORE matches value with it's
131
- # key if needed and Creates new instance of InputAnalysisResult.
132
- #
133
- # @param request [Contrast::Agent::Request] the current request context.
134
- # @param rule_id [String] The name of the Protect Rule.
135
- # @param input_type [Contrast::Agent::Reporting::InputType] The type of the user input.
136
- # @param value [String, Array<String>] the value of the input.
137
- #
138
- # @return res [Contrast::Agent::Reporting::InputAnalysisResult, nil]
139
- def create_new_input_result request, rule_id, input_type, value
140
- return unless Contrast::AGENT_LIB
141
-
142
- input_eval = Contrast::AGENT_LIB.eval_input(value,
143
- convert_input_type(input_type),
144
- Contrast::AGENT_LIB.rule_set[rule_id],
145
- Contrast::AGENT_LIB.eval_option[:PREFER_WORTH_WATCHING])
146
-
147
- ia_result = new_ia_result(rule_id, input_type, request.path, value)
148
- score = input_eval&.score || 0
149
- if score >= WORTHWATCHING_THRESHOLD
150
- ia_result.score_level = WORTHWATCHING
151
- ia_result.ids << self::WORTHWATCHING_MATCH
152
- else
153
- ia_result.score_level = IGNORE
154
- return
155
- end
156
-
157
- add_needed_key(request, ia_result, input_type, value) if KEYS_NEEDED.include?(input_type)
158
- ia_result
159
- end
160
-
161
- def append_result ia_analysis, result
162
- ia_analysis.results << result if result
163
- ia_analysis
164
- end
165
- end
166
- end
167
- end
168
- end
169
- end