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.
- 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
|