contrast-agent 5.1.0 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ext/cs__assess_kernel/cs__assess_kernel.c +7 -4
- data/ext/cs__assess_module/cs__assess_module.c +7 -7
- data/ext/cs__common/cs__common.c +4 -0
- data/ext/cs__common/cs__common.h +1 -0
- data/ext/cs__contrast_patch/cs__contrast_patch.c +52 -27
- data/ext/cs__contrast_patch/cs__contrast_patch.h +2 -0
- data/ext/cs__scope/cs__scope.c +747 -0
- data/ext/cs__scope/cs__scope.h +88 -0
- data/ext/cs__scope/extconf.rb +5 -0
- data/lib/contrast/agent/assess/contrast_event.rb +20 -13
- data/lib/contrast/agent/assess/contrast_object.rb +4 -1
- data/lib/contrast/agent/assess/policy/propagation_node.rb +2 -5
- data/lib/contrast/agent/assess/policy/propagator/match_data.rb +2 -0
- data/lib/contrast/agent/assess/policy/trigger_method.rb +4 -1
- data/lib/contrast/agent/assess/rule/response/{autocomplete_rule.rb → auto_complete_rule.rb} +4 -3
- data/lib/contrast/agent/assess/rule/response/base_rule.rb +12 -79
- data/lib/contrast/agent/assess/rule/response/body_rule.rb +109 -0
- data/lib/contrast/agent/assess/rule/response/cache_control_header_rule.rb +157 -0
- data/lib/contrast/agent/assess/rule/response/click_jacking_header_rule.rb +26 -0
- data/lib/contrast/agent/assess/rule/response/csp_header_insecure_rule.rb +14 -15
- data/lib/contrast/agent/assess/rule/response/csp_header_missing_rule.rb +5 -25
- data/lib/contrast/agent/assess/rule/response/framework/rails_support.rb +29 -0
- data/lib/contrast/agent/assess/rule/response/header_rule.rb +70 -0
- data/lib/contrast/agent/assess/rule/response/hsts_header_rule.rb +12 -36
- data/lib/contrast/agent/assess/rule/response/parameters_pollution_rule.rb +2 -1
- data/lib/contrast/agent/assess/rule/response/x_content_type_header_rule.rb +26 -0
- data/lib/contrast/agent/assess/rule/response/x_xss_protection_header_rule.rb +36 -0
- data/lib/contrast/agent/middleware.rb +1 -0
- data/lib/contrast/agent/patching/policy/after_load_patcher.rb +1 -3
- data/lib/contrast/agent/patching/policy/patch.rb +2 -6
- data/lib/contrast/agent/patching/policy/patcher.rb +1 -1
- data/lib/contrast/agent/protect/input_analyzer/input_analyzer.rb +94 -0
- data/lib/contrast/agent/protect/rule/base.rb +28 -1
- data/lib/contrast/agent/protect/rule/base_service.rb +10 -1
- data/lib/contrast/agent/protect/rule/cmd_injection.rb +2 -0
- data/lib/contrast/agent/protect/rule/deserialization.rb +6 -0
- data/lib/contrast/agent/protect/rule/http_method_tampering.rb +5 -1
- data/lib/contrast/agent/protect/rule/no_sqli.rb +1 -0
- data/lib/contrast/agent/protect/rule/path_traversal.rb +1 -0
- data/lib/contrast/agent/protect/rule/sqli/sqli_input_classification.rb +124 -0
- data/lib/contrast/agent/protect/rule/sqli/sqli_worth_watching.rb +121 -0
- data/lib/contrast/agent/protect/rule/sqli.rb +33 -0
- data/lib/contrast/agent/protect/rule/xxe.rb +4 -0
- data/lib/contrast/agent/reporting/input_analysis/input_analysis.rb +44 -0
- data/lib/contrast/agent/reporting/input_analysis/input_analysis_result.rb +115 -0
- data/lib/contrast/agent/reporting/input_analysis/input_type.rb +44 -0
- data/lib/contrast/agent/reporting/input_analysis/score_level.rb +21 -0
- data/lib/contrast/agent/reporting/report.rb +1 -0
- data/lib/contrast/agent/reporting/reporter.rb +8 -1
- data/lib/contrast/agent/reporting/reporting_events/finding.rb +69 -36
- data/lib/contrast/agent/reporting/reporting_events/finding_event.rb +88 -59
- data/lib/contrast/agent/reporting/reporting_events/{finding_object.rb → finding_event_object.rb} +24 -20
- data/lib/contrast/agent/reporting/reporting_events/finding_event_parent_object.rb +39 -0
- data/lib/contrast/agent/reporting/reporting_events/finding_event_property.rb +40 -0
- data/lib/contrast/agent/reporting/reporting_events/{finding_signature.rb → finding_event_signature.rb} +29 -24
- data/lib/contrast/agent/reporting/reporting_events/finding_event_source.rb +12 -8
- data/lib/contrast/agent/reporting/reporting_events/{finding_stack.rb → finding_event_stack.rb} +23 -19
- data/lib/contrast/agent/reporting/reporting_events/{finding_taint_range.rb → finding_event_taint_range.rb} +17 -15
- data/lib/contrast/agent/reporting/reporting_events/finding_request.rb +26 -53
- data/lib/contrast/agent/reporting/reporting_events/poll.rb +29 -0
- data/lib/contrast/agent/reporting/reporting_events/reporting_event.rb +5 -4
- data/lib/contrast/agent/reporting/reporting_events/route_discovery.rb +1 -0
- data/lib/contrast/agent/reporting/reporting_events/server_activity.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/audit.rb +10 -3
- data/lib/contrast/agent/reporting/reporting_utilities/endpoints.rb +0 -1
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client.rb +1 -0
- data/lib/contrast/agent/reporting/reporting_utilities/reporter_client_utils.rb +28 -20
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler.rb +1 -1
- data/lib/contrast/agent/reporting/reporting_utilities/response_handler_utils.rb +13 -1
- data/lib/contrast/agent/request_context.rb +6 -1
- data/lib/contrast/agent/request_context_extend.rb +85 -21
- data/lib/contrast/agent/scope.rb +102 -107
- data/lib/contrast/agent/service_heartbeat.rb +45 -2
- data/lib/contrast/agent/version.rb +1 -1
- data/lib/contrast/api/decorators/bot_blocker.rb +37 -0
- data/lib/contrast/api/decorators/ip_denylist.rb +37 -0
- data/lib/contrast/api/decorators/rasp_rule_sample.rb +29 -0
- data/lib/contrast/api/decorators/user_input.rb +11 -1
- data/lib/contrast/api/decorators/virtual_patch.rb +34 -0
- data/lib/contrast/components/logger.rb +5 -0
- data/lib/contrast/components/protect.rb +4 -2
- data/lib/contrast/components/scope.rb +98 -91
- data/lib/contrast/config/agent_configuration.rb +58 -12
- data/lib/contrast/config/api_configuration.rb +100 -12
- data/lib/contrast/config/api_proxy_configuration.rb +55 -3
- data/lib/contrast/config/application_configuration.rb +114 -15
- data/lib/contrast/config/assess_configuration.rb +106 -12
- data/lib/contrast/config/assess_rules_configuration.rb +44 -3
- data/lib/contrast/config/base_configuration.rb +1 -0
- data/lib/contrast/config/certification_configuration.rb +74 -3
- data/lib/contrast/config/exception_configuration.rb +61 -3
- data/lib/contrast/config/heap_dump_configuration.rb +101 -17
- data/lib/contrast/config/inventory_configuration.rb +64 -3
- data/lib/contrast/config/logger_configuration.rb +46 -3
- data/lib/contrast/config/protect_rule_configuration.rb +36 -9
- data/lib/contrast/config/protect_rules_configuration.rb +120 -17
- data/lib/contrast/config/request_audit_configuration.rb +68 -3
- data/lib/contrast/config/ruby_configuration.rb +96 -22
- data/lib/contrast/config/sampling_configuration.rb +76 -10
- data/lib/contrast/config/server_configuration.rb +56 -11
- data/lib/contrast/configuration.rb +6 -3
- data/lib/contrast/logger/cef_log.rb +151 -0
- data/lib/contrast/utils/hash_digest.rb +14 -6
- data/lib/contrast/utils/log_utils.rb +114 -0
- data/lib/contrast/utils/middleware_utils.rb +6 -7
- data/lib/contrast/utils/net_http_base.rb +12 -9
- data/lib/contrast/utils/patching/policy/patch_utils.rb +0 -4
- data/lib/contrast.rb +4 -3
- data/ruby-agent.gemspec +1 -1
- data/service_executables/VERSION +1 -1
- data/service_executables/linux/contrast-service +0 -0
- data/service_executables/mac/contrast-service +0 -0
- metadata +41 -21
- data/lib/contrast/agent/assess/rule/response/cachecontrol_rule.rb +0 -184
- data/lib/contrast/agent/assess/rule/response/clickjacking_rule.rb +0 -66
- data/lib/contrast/agent/assess/rule/response/x_content_type_rule.rb +0 -52
- data/lib/contrast/agent/assess/rule/response/x_xss_protection_rule.rb +0 -53
- data/lib/contrast/extension/kernel.rb +0 -54
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'contrast/agent/assess/rule/response/base_rule'
|
|
5
|
-
require 'contrast/utils/string_utils'
|
|
6
|
-
require 'json'
|
|
7
|
-
|
|
8
|
-
module Contrast
|
|
9
|
-
module Agent
|
|
10
|
-
module Assess
|
|
11
|
-
module Rule
|
|
12
|
-
module Response
|
|
13
|
-
# These rules check the content of the HTTP Response to determine if the body or the headers include and/or
|
|
14
|
-
# set incorrectly the cache-control header
|
|
15
|
-
class Cachecontrol < BaseRule
|
|
16
|
-
def rule_id
|
|
17
|
-
'cache-controls-missing'
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
protected
|
|
21
|
-
|
|
22
|
-
HEADER_KEY = 'Cache-Control'.cs__freeze
|
|
23
|
-
ACCEPTED_VALUES = %w[no-store no-cache].cs__freeze
|
|
24
|
-
|
|
25
|
-
# Rules discern which responses they can/should analyze.
|
|
26
|
-
#
|
|
27
|
-
# @param response [Contrast::Agent::Response] the response of the application
|
|
28
|
-
def analyze_response? response
|
|
29
|
-
super && body?(response)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# Determine if the Response violates the Rule or not. If it does, return the evidence that proves it so.
|
|
33
|
-
#
|
|
34
|
-
# @param response [Contrast::Agent::Response] the response of the application
|
|
35
|
-
# @return [Hash, nil] the evidence required to prove the violation of the rule
|
|
36
|
-
def violated? response
|
|
37
|
-
# This rule is violated if the header is not there
|
|
38
|
-
# or if it's there, but the value is not 'no-store' or 'no-cache'
|
|
39
|
-
headers = response.headers
|
|
40
|
-
header_key_sym = HEADER_KEY.to_sym
|
|
41
|
-
cache_control = headers[HEADER_KEY] || headers[header_key_sym]
|
|
42
|
-
if cache_control && !valid_header?(cache_control)
|
|
43
|
-
return to_cachecontrol_rule('header', 'cache-control', cache_control)
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
body = response.body
|
|
47
|
-
# check if the meta tag is include it
|
|
48
|
-
tags = meta_tags(body)
|
|
49
|
-
|
|
50
|
-
tags.each do |tag|
|
|
51
|
-
return to_cachecontrol_rule('meta', 'pragma', tag[HTML_PROP]) if meta_cache_tag? tag[HTML_PROP]
|
|
52
|
-
end
|
|
53
|
-
# we should return if header not presented and no tags are detected
|
|
54
|
-
return {} if !(headers.key?(HEADER_KEY) || headers.key?(header_key_sym)) && tags.empty?
|
|
55
|
-
|
|
56
|
-
nil
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def valid_header? header
|
|
60
|
-
ACCEPTED_VALUES.any? { |val| header.include?(val) || header == val }
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# Find the tags in this body, if any, so as to determine if they violate this rule.
|
|
64
|
-
#
|
|
65
|
-
# @param body [String,nil]
|
|
66
|
-
# @return [Array<Hash>] the tags of this body, as well as their start and end indexes.
|
|
67
|
-
def meta_tags body
|
|
68
|
-
tags = []
|
|
69
|
-
body_start = 0
|
|
70
|
-
|
|
71
|
-
# meta tags are stored in the <head></head> section
|
|
72
|
-
head_section = body&.split(head_tag)
|
|
73
|
-
return [] unless head_section
|
|
74
|
-
|
|
75
|
-
potential_tags = head_section.map { |el| el.split(meta_start) }
|
|
76
|
-
potential_tags.flatten.each do |potential_tag|
|
|
77
|
-
next unless potential_tag
|
|
78
|
-
next unless tag_openings.any? { |opening| potential_tag.starts_with?(opening) }
|
|
79
|
-
|
|
80
|
-
body_start = body.index(meta_start, body_start)
|
|
81
|
-
next unless body_start
|
|
82
|
-
|
|
83
|
-
tag_stop = potential_tag.index('>').to_i
|
|
84
|
-
next unless tag_stop
|
|
85
|
-
|
|
86
|
-
body_close = body_start + 6 + tag_stop
|
|
87
|
-
tags << capture(body, body_start, body_close, tag_stop)
|
|
88
|
-
body_start = body_close
|
|
89
|
-
end
|
|
90
|
-
tags
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def meta_start
|
|
94
|
-
/<meta/i
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def head_tag
|
|
98
|
-
/<head>/i
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def tag_openings
|
|
102
|
-
[' ', "\n", "\r", "\t"]
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
def accepted_http_values
|
|
106
|
-
[/'cache-control'/i, /"cache-control"/i]
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
def accepted_values
|
|
110
|
-
[/'no-cache'/i, /"no-cache"/i, /"no-store"/i, /'no-store'/i]
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Determine if the given metatag does not have a valid cache-control tag.
|
|
114
|
-
# Meta tags has the option to set http-equiv and content to set the http response header
|
|
115
|
-
# to define for the document
|
|
116
|
-
#
|
|
117
|
-
# @param tag [String] the meta tag
|
|
118
|
-
# @return [Boolean, nil]
|
|
119
|
-
def meta_cache_tag? tag
|
|
120
|
-
# Here we should determine the index of the needed keys
|
|
121
|
-
# http-equiv and content
|
|
122
|
-
http_equiv_idx = tag =~ /http-equiv=/i
|
|
123
|
-
return false unless http_equiv_idx
|
|
124
|
-
|
|
125
|
-
content_idx = tag =~ /content=/i
|
|
126
|
-
return false unless content_idx
|
|
127
|
-
|
|
128
|
-
# determine the value of the http-equiv if it's cache-control
|
|
129
|
-
http_equiv_idx += 11
|
|
130
|
-
is_valid = accepted_http_values.any? { |el| (tag =~ el) == http_equiv_idx }
|
|
131
|
-
return false unless is_valid
|
|
132
|
-
|
|
133
|
-
content_idx += 8
|
|
134
|
-
return false if accepted_values.any? { |value| (tag =~ value) == content_idx }
|
|
135
|
-
|
|
136
|
-
true
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
# This method allows to change the evidence we attach and the way we attach it
|
|
140
|
-
# Change it accordingly the rule you work on
|
|
141
|
-
#
|
|
142
|
-
# @param evidence [Hash] the properties required to build this finding.
|
|
143
|
-
# @param finding [Contrast::Api::Dtm::Finding] finding to attach the evidence to
|
|
144
|
-
def build_evidence evidence, finding
|
|
145
|
-
evidence.each_pair do |key, value|
|
|
146
|
-
finding.properties[key] = Contrast::Utils::StringUtils.protobuf_format(value)
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
# This method accepts the violation and transforms it to the proper hash
|
|
151
|
-
# before return in as violation
|
|
152
|
-
#
|
|
153
|
-
# @param type [String] String of Header or META of the type
|
|
154
|
-
# @param name [String] String of either cache-control or pragma
|
|
155
|
-
# @param value [String] String of the violated value
|
|
156
|
-
def to_cachecontrol_rule type, name, value
|
|
157
|
-
{ data: { type: type, name: name, value: value }.to_s }
|
|
158
|
-
end
|
|
159
|
-
|
|
160
|
-
# Capture the information needed to build the properties of this finding by parsing out from the body
|
|
161
|
-
#
|
|
162
|
-
# @param body [String] the entire HTTP Response body
|
|
163
|
-
# @param body_start [Integer] the start of the range to take from the body
|
|
164
|
-
# @param body_close [Integer] the end of the range to take from the body
|
|
165
|
-
# @param tag_stop [Integer] the index of the end of the html tag from its start
|
|
166
|
-
# @return [Hash]
|
|
167
|
-
def capture body, body_start, body_close, tag_stop
|
|
168
|
-
# In this situation we don't need to capture before and after the meta tag, as this may produce an error
|
|
169
|
-
# So if we capture 30-50 chars before and after the tag, we may capture part of the tag, we want to
|
|
170
|
-
# inspect and eventually this wil return wrong string. Because of that - we split the <head> and take
|
|
171
|
-
# each meta tag and examine it
|
|
172
|
-
tag = {}
|
|
173
|
-
# we dont need to capture here before or after the meta tag
|
|
174
|
-
tag[HTML_PROP] = body[body_start...body_close]
|
|
175
|
-
tag[START_PROP] = body_start
|
|
176
|
-
tag[END_PROP] = tag[START_PROP] + 6 + tag_stop
|
|
177
|
-
tag
|
|
178
|
-
end
|
|
179
|
-
end
|
|
180
|
-
end
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
end
|
|
184
|
-
end
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'contrast/agent/assess/rule/response/base_rule'
|
|
5
|
-
require 'contrast/utils/string_utils'
|
|
6
|
-
|
|
7
|
-
module Contrast
|
|
8
|
-
module Agent
|
|
9
|
-
module Assess
|
|
10
|
-
module Rule
|
|
11
|
-
module Response
|
|
12
|
-
# These rules check the content of the HTTP Response to determine if the headers contains the required header
|
|
13
|
-
class Clickjacking < BaseRule
|
|
14
|
-
def rule_id
|
|
15
|
-
'clickjacking-control-missing'
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
protected
|
|
19
|
-
|
|
20
|
-
HEADER_KEY = 'X-Frame-Options'.cs__freeze
|
|
21
|
-
HEADER_KEY_SYM = HEADER_KEY.to_sym
|
|
22
|
-
ACCEPTED_VALUES = [/^deny/i, /^sameorigin/i].cs__freeze
|
|
23
|
-
|
|
24
|
-
# Rules discern which responses they can/should analyze.
|
|
25
|
-
#
|
|
26
|
-
# @param response [Contrast::Agent::Response] the response of the application
|
|
27
|
-
def analyze_response? response
|
|
28
|
-
super && headers?(response)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Determine if the Response violates the Rule or not. If it does, return the evidence that proves it so.
|
|
32
|
-
#
|
|
33
|
-
# @param response [Contrast::Agent::Response] the response of the application
|
|
34
|
-
# @return [Hash, nil] the evidence required to prove the violation of the rule
|
|
35
|
-
def violated? response
|
|
36
|
-
headers = response.headers
|
|
37
|
-
cache_control = headers[HEADER_KEY] || headers[HEADER_KEY_SYM]
|
|
38
|
-
return unsafe_response unless cache_control
|
|
39
|
-
return unsafe_response(cache_control) unless valid_header?(cache_control)
|
|
40
|
-
|
|
41
|
-
nil
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def valid_header? header
|
|
45
|
-
ACCEPTED_VALUES.any? { |val| header =~ val }
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def unsafe_response value = ''
|
|
49
|
-
{ data: value }
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Change it accordingly the rule you work on
|
|
53
|
-
#
|
|
54
|
-
# @param evidence [Hash] the properties required to build this finding.
|
|
55
|
-
# @param finding [Contrast::Api::Dtm::Finding] finding to attach the evidence to
|
|
56
|
-
def build_evidence evidence, finding
|
|
57
|
-
evidence.each_pair do |key, value|
|
|
58
|
-
finding.properties[key] = Contrast::Utils::StringUtils.protobuf_format(value)
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
|
-
end
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'contrast/agent/assess/rule/response/base_rule'
|
|
5
|
-
require 'contrast/utils/string_utils'
|
|
6
|
-
|
|
7
|
-
module Contrast
|
|
8
|
-
module Agent
|
|
9
|
-
module Assess
|
|
10
|
-
module Rule
|
|
11
|
-
module Response
|
|
12
|
-
# These rules check the content of the HTTP Response to determine if the response contains the needed header
|
|
13
|
-
class XContentType < BaseRule
|
|
14
|
-
def rule_id
|
|
15
|
-
'xcontenttype-header-missing'
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
protected
|
|
19
|
-
|
|
20
|
-
HEADER_KEY = 'X-Content-Type-Options'.cs__freeze
|
|
21
|
-
HEADER_KEY_SYM = HEADER_KEY.to_sym
|
|
22
|
-
ACCEPTED_VALUE = /^nosniff/i.cs__freeze
|
|
23
|
-
|
|
24
|
-
# Rules discern which responses they can/should analyze.
|
|
25
|
-
#
|
|
26
|
-
# @param response [Contrast::Agent::Response] the response of the application
|
|
27
|
-
def analyze_response? response
|
|
28
|
-
super && headers?(response)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Determine if the Response violates the Rule or not. If it does, return the evidence that proves it so.
|
|
32
|
-
#
|
|
33
|
-
# @param response [Contrast::Agent::Response] the response of the application
|
|
34
|
-
# @return [Hash, nil] the evidence required to prove the violation of the rule
|
|
35
|
-
def violated? response
|
|
36
|
-
headers = response.headers
|
|
37
|
-
x_content_type = headers[HEADER_KEY] || headers[HEADER_KEY_SYM]
|
|
38
|
-
return unsafe_response unless x_content_type
|
|
39
|
-
return unsafe_response x_content_type unless ACCEPTED_VALUE.match?(x_content_type)
|
|
40
|
-
|
|
41
|
-
nil
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def unsafe_response value = ''
|
|
45
|
-
{ data: value }
|
|
46
|
-
end
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'contrast/agent/assess/rule/response/base_rule'
|
|
5
|
-
require 'contrast/utils/string_utils'
|
|
6
|
-
|
|
7
|
-
module Contrast
|
|
8
|
-
module Agent
|
|
9
|
-
module Assess
|
|
10
|
-
module Rule
|
|
11
|
-
module Response
|
|
12
|
-
# These rules check the content of the HTTP Response to determine if the response contains the needed header
|
|
13
|
-
class XXssProtection < BaseRule
|
|
14
|
-
def rule_id
|
|
15
|
-
'xxssprotection-header-disabled'
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
protected
|
|
19
|
-
|
|
20
|
-
HEADER_KEY = 'X-XSS-Protection'.cs__freeze
|
|
21
|
-
HEADER_KEY_SYM = HEADER_KEY.to_sym
|
|
22
|
-
ACCEPTED_VALUE = /^1/.cs__freeze
|
|
23
|
-
|
|
24
|
-
# Rules discern which responses they can/should analyze.
|
|
25
|
-
#
|
|
26
|
-
# @param response [Contrast::Agent::Response] the response of the application
|
|
27
|
-
def analyze_response? response
|
|
28
|
-
super && headers?(response)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Determine if the Response violates the Rule or not. If it does, return the evidence that proves it so.
|
|
32
|
-
#
|
|
33
|
-
# @param response [Contrast::Agent::Response] the response of the application
|
|
34
|
-
# @return [Hash, nil] the evidence required to prove the violation of the rule
|
|
35
|
-
def violated? response
|
|
36
|
-
headers = response.headers
|
|
37
|
-
x_xss_protection = headers[HEADER_KEY] || headers[HEADER_KEY_SYM]
|
|
38
|
-
# header is safe by default so only need to return finding on failed value match
|
|
39
|
-
return unless x_xss_protection
|
|
40
|
-
return unsafe_response x_xss_protection unless ACCEPTED_VALUE.match?(x_xss_protection)
|
|
41
|
-
|
|
42
|
-
nil
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
def unsafe_response value = ''
|
|
46
|
-
{ data: value }
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|
|
53
|
-
end
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# Copyright (c) 2022 Contrast Security, Inc. See https://www.contrastsecurity.com/enduser-terms-0317a for more details.
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require 'contrast/components/scope'
|
|
5
|
-
|
|
6
|
-
# This is a reasonable place for the Kernel#catch hook to live.
|
|
7
|
-
# No current plans for component re-design, but if we had some kind of
|
|
8
|
-
# "do this when a component is hooked in" thing, this would live there.
|
|
9
|
-
# For now, it's over-engineering to live anywhere else. -ajm
|
|
10
|
-
module Kernel # :nodoc:
|
|
11
|
-
alias_method :cs__catch, :catch
|
|
12
|
-
|
|
13
|
-
# In the event of a `throw`, we need to override `catch`
|
|
14
|
-
# to save & restore scope state:
|
|
15
|
-
#
|
|
16
|
-
# scope_level == 0
|
|
17
|
-
#
|
|
18
|
-
# catch(:abc) do
|
|
19
|
-
# with_contrast_scope do
|
|
20
|
-
# throw :abc # will leak
|
|
21
|
-
# end
|
|
22
|
-
# end
|
|
23
|
-
#
|
|
24
|
-
# scope_level == 1
|
|
25
|
-
#
|
|
26
|
-
# Frankly, this isn't how scope should be used. This is in place of
|
|
27
|
-
# proper `ensure` blocks within the instrumentation call stack.
|
|
28
|
-
# This will actually /create/ scope leaks if you're doing something like:
|
|
29
|
-
#
|
|
30
|
-
# catch(:ohno) do
|
|
31
|
-
# enter scope
|
|
32
|
-
# end
|
|
33
|
-
#
|
|
34
|
-
# abc()
|
|
35
|
-
#
|
|
36
|
-
# exit scope
|
|
37
|
-
#
|
|
38
|
-
# i.e. if you intend to change net scope across a catch block boundary.
|
|
39
|
-
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
def catch *args, &block
|
|
43
|
-
# Save current scope level
|
|
44
|
-
scope_level = ::Contrast::SCOPE.scope_for_current_ec.instance_variable_get(:@contrast_scope)
|
|
45
|
-
|
|
46
|
-
# Run original catch with block.
|
|
47
|
-
retval = cs__catch(*args, &block)
|
|
48
|
-
|
|
49
|
-
# Restore scope.
|
|
50
|
-
::Contrast::SCOPE.scope_for_current_ec.instance_variable_set(:@contrast_scope, scope_level)
|
|
51
|
-
|
|
52
|
-
retval
|
|
53
|
-
end
|
|
54
|
-
end
|