consolidate escape sequence capturing in one validation, add suspenders to check if one snuck by
This commit is contained in:
Родитель
0b26d92ba6
Коммит
87dba71b92
|
@ -105,6 +105,11 @@ module SecureHeaders
|
||||||
source_list = @config.directive_value(directive)
|
source_list = @config.directive_value(directive)
|
||||||
if source_list != OPT_OUT && source_list && source_list.any?
|
if source_list != OPT_OUT && source_list && source_list.any?
|
||||||
minified_source_list = minify_source_list(directive, source_list).join(" ")
|
minified_source_list = minify_source_list(directive, source_list).join(" ")
|
||||||
|
if minified_source_list =~ ESCAPE_SEQUENCE
|
||||||
|
# Should not happen. Just in case.
|
||||||
|
raise ContentSecurityPolicyConfigError.new("generated #{directive} contains a #{$1.inspect} in #{minified_source_list.inspect}")
|
||||||
|
end
|
||||||
|
|
||||||
[symbol_to_hyphen_case(directive), minified_source_list].join(" ").strip
|
[symbol_to_hyphen_case(directive), minified_source_list].join(" ").strip
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -329,7 +329,7 @@ module SecureHeaders
|
||||||
return if boolean?(sandbox_token_expression) && sandbox_token_expression == true
|
return if boolean?(sandbox_token_expression) && sandbox_token_expression == true
|
||||||
ensure_array_of_strings!(directive, sandbox_token_expression)
|
ensure_array_of_strings!(directive, sandbox_token_expression)
|
||||||
valid = sandbox_token_expression.compact.all? do |v|
|
valid = sandbox_token_expression.compact.all? do |v|
|
||||||
v.is_a?(String) && v.start_with?("allow-") && v !~ ESCAPE_SEQUENCE
|
v.is_a?(String) && v.start_with?("allow-")
|
||||||
end
|
end
|
||||||
if !valid
|
if !valid
|
||||||
raise ContentSecurityPolicyConfigError.new("#{directive} must be True or an array of zero or more sandbox token strings (ex. allow-forms). Was #{sandbox_token_expression.inspect}")
|
raise ContentSecurityPolicyConfigError.new("#{directive} must be True or an array of zero or more sandbox token strings (ex. allow-forms). Was #{sandbox_token_expression.inspect}")
|
||||||
|
@ -380,7 +380,18 @@ module SecureHeaders
|
||||||
end
|
end
|
||||||
|
|
||||||
def ensure_array_of_strings!(directive, value)
|
def ensure_array_of_strings!(directive, value)
|
||||||
if (!value.is_a?(Array) || !value.compact.all? { |v| v.is_a?(String) })
|
unless value.is_a?(Array)
|
||||||
|
raise ContentSecurityPolicyConfigError.new("#{directive} must be an array of strings")
|
||||||
|
end
|
||||||
|
|
||||||
|
all_valid_strings = value.compact.all? do |v|
|
||||||
|
if v =~ ESCAPE_SEQUENCE
|
||||||
|
raise ContentSecurityPolicyConfigError.new("#{directive} contains a #{$1.inspect} in #{v.inspect}")
|
||||||
|
end
|
||||||
|
v.is_a?(String)
|
||||||
|
end
|
||||||
|
|
||||||
|
unless all_valid_strings
|
||||||
raise ContentSecurityPolicyConfigError.new("#{directive} must be an array of strings")
|
raise ContentSecurityPolicyConfigError.new("#{directive} must be an array of strings")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -391,10 +402,6 @@ module SecureHeaders
|
||||||
if ContentSecurityPolicy::DEPRECATED_SOURCE_VALUES.include?(expression)
|
if ContentSecurityPolicy::DEPRECATED_SOURCE_VALUES.include?(expression)
|
||||||
raise ContentSecurityPolicyConfigError.new("#{directive} contains an invalid keyword source (#{expression}). This value must be single quoted.")
|
raise ContentSecurityPolicyConfigError.new("#{directive} contains an invalid keyword source (#{expression}). This value must be single quoted.")
|
||||||
end
|
end
|
||||||
|
|
||||||
if expression =~ ESCAPE_SEQUENCE
|
|
||||||
raise ContentSecurityPolicyConfigError.new("#{directive} contains a #{$1.inspect} in #{expression.inspect}")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -113,7 +113,13 @@ module SecureHeaders
|
||||||
it "disallows newlines in configs" do
|
it "disallows newlines in configs" do
|
||||||
expect do
|
expect do
|
||||||
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w('self'), script_src: %w(mycdn.com), object_src: ["http://foo.com \n script-src *"]))
|
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_src: %w('self'), script_src: %w(mycdn.com), object_src: ["http://foo.com \n script-src *"]))
|
||||||
end.to raise_error(ContentSecurityPolicyConfigError, %r{object_src contains a "\\n" in "http://foo.com \\n script-src})
|
end.to raise_error(ContentSecurityPolicyConfigError, %r(object_src contains a "\\n" in "http://foo.com \\n script-src))
|
||||||
|
end
|
||||||
|
|
||||||
|
it "catches semicolons that somehow bypass validation" do
|
||||||
|
expect do
|
||||||
|
ContentSecurityPolicy.new(ContentSecurityPolicyConfig.new(default_src: %w('self'), script_src: %w(mycdn.com), object_src: ["http://foo.com ; script-src *"])).value
|
||||||
|
end.to raise_error(ContentSecurityPolicyConfigError, %(generated object_src contains a ";" in "foo.com ; script-src *"))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "allows nil values" do
|
it "allows nil values" do
|
||||||
|
@ -141,16 +147,16 @@ module SecureHeaders
|
||||||
end.to raise_error(ContentSecurityPolicyConfigError, %(sandbox must be True or an array of zero or more sandbox token strings (ex. allow-forms). Was ["steve"]))
|
end.to raise_error(ContentSecurityPolicyConfigError, %(sandbox must be True or an array of zero or more sandbox token strings (ex. allow-forms). Was ["steve"]))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "accepts anything of the form allow-* as a sandbox value " do
|
it "accepts anything of the form allow-* as a sandbox value" do
|
||||||
expect do
|
expect do
|
||||||
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(sandbox: ["allow-foo"])))
|
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(sandbox: ["allow-foo"])))
|
||||||
end.to_not raise_error
|
end.to_not raise_error
|
||||||
end
|
end
|
||||||
|
|
||||||
it "rejects escapes in sandbox value " do
|
it "rejects escapes in sandbox value" do
|
||||||
expect do
|
expect do
|
||||||
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(sandbox: ["allow-; script-src foo"])))
|
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(sandbox: ["allow-; script-src foo"])))
|
||||||
end.to raise_error(ContentSecurityPolicyConfigError, %(sandbox must be True or an array of zero or more sandbox token strings (ex. allow-forms). Was ["allow-; script-src foo"]))
|
end.to raise_error(ContentSecurityPolicyConfigError, %(sandbox contains a ";" in "allow-; script-src foo"))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "accepts true as a sandbox policy" do
|
it "accepts true as a sandbox policy" do
|
||||||
|
@ -168,10 +174,10 @@ module SecureHeaders
|
||||||
it "rejects escape values as plugin-type value" do
|
it "rejects escape values as plugin-type value" do
|
||||||
expect do
|
expect do
|
||||||
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(plugin_types: [";/script-src*"])))
|
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(plugin_types: [";/script-src*"])))
|
||||||
end.to raise_error(ContentSecurityPolicyConfigError, "plugin_types must be an array of valid media types (ex. application/pdf)")
|
end.to raise_error(ContentSecurityPolicyConfigError, %(plugin_types contains a ";" in ";/script-src*"))
|
||||||
end
|
end
|
||||||
|
|
||||||
it "accepts anything of the form type/subtype as a plugin-type value " do
|
it "accepts anything of the form type/subtype as a plugin-type value" do
|
||||||
expect do
|
expect do
|
||||||
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(plugin_types: ["application/pdf"])))
|
ContentSecurityPolicy.validate_config!(ContentSecurityPolicyConfig.new(default_opts.merge(plugin_types: ["application/pdf"])))
|
||||||
end.to_not raise_error
|
end.to_not raise_error
|
||||||
|
|
Загрузка…
Ссылка в новой задаче