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.
- checksums.yaml +4 -4
- data/lib/contrast/agent/assess/policy/policy_node.rb +25 -6
- data/lib/contrast/agent/assess/policy/propagator/response.rb +64 -0
- data/lib/contrast/agent/assess/policy/propagator.rb +1 -0
- data/lib/contrast/agent/assess/policy/source_method.rb +5 -0
- data/lib/contrast/agent/assess/rule/response/body_rule.rb +22 -7
- data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +4 -1
- data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +62 -23
- data/lib/contrast/agent/protect/input_analyzer/worth_watching_analyzer.rb +37 -4
- data/lib/contrast/agent/protect/rule/base.rb +5 -1
- data/lib/contrast/agent/protect/rule/bot_blocker/bot_blocker_input_classification.rb +27 -11
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_base_rule.rb +0 -1
- data/lib/contrast/agent/protect/rule/cmdi/cmdi_input_classification.rb +2 -2
- data/lib/contrast/agent/protect/rule/input_classification/base.rb +191 -0
- data/lib/contrast/agent/protect/rule/input_classification/base64_statistic.rb +71 -0
- data/lib/contrast/agent/protect/rule/input_classification/cached_result.rb +37 -0
- data/lib/contrast/agent/protect/rule/input_classification/encoding.rb +109 -0
- data/lib/contrast/agent/protect/rule/input_classification/encoding_rates.rb +47 -0
- data/lib/contrast/agent/protect/rule/input_classification/extendable.rb +80 -0
- data/lib/contrast/agent/protect/rule/input_classification/lru_cache.rb +198 -0
- data/lib/contrast/agent/protect/rule/input_classification/match_rates.rb +66 -0
- data/lib/contrast/agent/protect/rule/input_classification/rates.rb +53 -0
- data/lib/contrast/agent/protect/rule/input_classification/statistics.rb +115 -0
- data/lib/contrast/agent/protect/rule/input_classification/utils.rb +23 -0
- data/lib/contrast/agent/protect/rule/no_sqli/no_sqli_input_classification.rb +17 -7
- data/lib/contrast/agent/protect/rule/path_traversal/path_traversal_input_classification.rb +18 -15
- data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +2 -2
- data/lib/contrast/agent/protect/rule/unsafe_file_upload/unsafe_file_upload_input_classification.rb +18 -15
- data/lib/contrast/agent/protect/rule/xss/reflected_xss_input_classification.rb +19 -17
- data/lib/contrast/agent/reporting/attack_result/attack_result.rb +6 -0
- data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +2 -7
- data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +11 -0
- data/lib/contrast/agent/reporting/input_analysis/input_type.rb +33 -1
- data/lib/contrast/agent/reporting/masker/masker_utils.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_events/application_defend_activity.rb +1 -0
- data/lib/contrast/agent/reporting/reporting_events/application_defend_attacker_activity.rb +1 -0
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +1 -1
- data/lib/contrast/agent/telemetry/base.rb +28 -2
- data/lib/contrast/agent/telemetry/base64_hash.rb +55 -0
- data/lib/contrast/agent/telemetry/cache_hash.rb +55 -0
- data/lib/contrast/agent/telemetry/client.rb +10 -2
- data/lib/contrast/agent/telemetry/exception/obfuscate.rb +4 -3
- data/lib/contrast/agent/telemetry/{hash.rb → exception_hash.rb} +1 -1
- data/lib/contrast/agent/telemetry/identifier.rb +13 -26
- data/lib/contrast/agent/telemetry/input_analysis_cache_event.rb +27 -0
- data/lib/contrast/agent/telemetry/input_analysis_encoding_event.rb +26 -0
- data/lib/contrast/agent/telemetry/input_analysis_event.rb +91 -0
- data/lib/contrast/agent/telemetry/metric_event.rb +12 -0
- data/lib/contrast/agent/telemetry/startup_metrics_event.rb +0 -8
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/components/assess.rb +33 -6
- data/lib/contrast/components/base.rb +4 -2
- data/lib/contrast/components/config.rb +6 -6
- data/lib/contrast/components/protect.rb +11 -1
- data/lib/contrast/components/sampling.rb +15 -10
- data/lib/contrast/config/diagnostics/command_line.rb +2 -2
- data/lib/contrast/config/diagnostics/environment_variables.rb +5 -2
- data/lib/contrast/config/diagnostics/tools.rb +15 -5
- data/lib/contrast/config/yaml_file.rb +8 -0
- data/lib/contrast/configuration.rb +61 -29
- data/lib/contrast/framework/rails/support.rb +3 -0
- data/lib/contrast/logger/application.rb +3 -3
- data/lib/contrast/utils/assess/event_limit_utils.rb +13 -13
- data/lib/contrast/utils/assess/propagation_method_utils.rb +2 -0
- data/lib/contrast/utils/metrics_hash.rb +1 -1
- data/lib/contrast/utils/object_share.rb +2 -1
- data/lib/contrast/utils/os.rb +1 -9
- data/lib/contrast/utils/response_utils.rb +12 -0
- data/lib/contrast/utils/timer.rb +2 -0
- data/lib/contrast.rb +9 -2
- data/resources/assess/policy.json +80 -3
- data/ruby-agent.gemspec +1 -1
- metadata +22 -6
- 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.
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
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.
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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-
|
20
|
+
KEY_REGEXP = /[a-zA-Z0-9._-]{1,63}/.cs__freeze
|
21
21
|
|
22
22
|
def initialize data_type, *several_variants
|
23
23
|
super
|
data/lib/contrast/utils/os.rb
CHANGED
@@ -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
|
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
|
data/lib/contrast/utils/timer.rb
CHANGED
@@ -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/
|
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 = (
|
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.
|
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.
|
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-
|
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.
|
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.
|
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/
|
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
|