contrast-agent 7.2.0 → 7.3.1

Sign up to get free protection for your applications and to get access to all the features.
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