aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
authorAndrew White <andrew.white@unboxed.co>2018-04-18 10:44:48 +0300
committerAndrey Novikov <envek@envek.name>2018-04-18 10:51:02 +0300
commit35970cbf3f64a2bcce56af945da66313896014c3 (patch)
treecc4dca70caed63620cf4d5b704b9af39d3275483 /actionpack/lib
parentb9b660728ff771424e423ef917ad81ffadd50210 (diff)
downloadrails-35970cbf3f64a2bcce56af945da66313896014c3.tar.gz
rails-35970cbf3f64a2bcce56af945da66313896014c3.tar.bz2
rails-35970cbf3f64a2bcce56af945da66313896014c3.zip
Pass nonce to CSP policy from outside
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_dispatch/http/content_security_policy.rb55
1 files changed, 24 insertions, 31 deletions
diff --git a/actionpack/lib/action_dispatch/http/content_security_policy.rb b/actionpack/lib/action_dispatch/http/content_security_policy.rb
index 0573f13f94..82d348fa22 100644
--- a/actionpack/lib/action_dispatch/http/content_security_policy.rb
+++ b/actionpack/lib/action_dispatch/http/content_security_policy.rb
@@ -21,7 +21,8 @@ module ActionDispatch #:nodoc:
return response if policy_present?(headers)
if policy = request.content_security_policy
- headers[header_name(request)] = policy.build(request)
+ nonce = request.content_security_policy_nonce
+ headers[header_name(request)] = policy.build(request.controller_instance, nonce)
end
response
@@ -95,14 +96,6 @@ module ActionDispatch #:nodoc:
end
end
- class NonceGenerator
- def call(request)
- if nonce = request&.content_security_policy_nonce
- "'nonce-#{nonce}'"
- end
- end
- end
-
MAPPINGS = {
self: "'self'",
unsafe_eval: "'unsafe-eval'",
@@ -133,12 +126,14 @@ module ActionDispatch #:nodoc:
manifest_src: "manifest-src",
media_src: "media-src",
object_src: "object-src",
- # script_src handled differently
+ script_src: "script-src",
style_src: "style-src",
worker_src: "worker-src"
}.freeze
- private_constant :MAPPINGS, :DIRECTIVES
+ NONCE_DIRECTIVES = %w[script-src].freeze
+
+ private_constant :MAPPINGS, :DIRECTIVES, :NONCE_DIRECTIVES
attr_reader :directives
@@ -161,15 +156,6 @@ module ActionDispatch #:nodoc:
end
end
- def script_src(*sources)
- if sources.first
- @directives["script-src"] = apply_mappings(sources)
- @directives["script-src"] << NonceGenerator.new
- else
- @directives.delete("script-src")
- end
- end
-
def block_all_mixed_content(enabled = true)
if enabled
@directives["block-all-mixed-content"] = true
@@ -216,8 +202,8 @@ module ActionDispatch #:nodoc:
end
end
- def build(request = nil)
- build_directives(request).compact.join("; ")
+ def build(context = nil, nonce = nil)
+ build_directives(context, nonce).compact.join("; ")
end
private
@@ -240,10 +226,15 @@ module ActionDispatch #:nodoc:
end
end
- def build_directives(request)
+ def build_directives(context, nonce)
@directives.map do |directive, sources|
if sources.is_a?(Array)
- "#{directive} #{build_directive(sources, request).compact.join(' ')}"
+ "#{directive} #{build_directive(sources, context).join(' ')}"
+ if nonce && nonce_directive?(directive)
+ "#{directive} #{build_directive(sources, context).join(' ')} 'nonce-#{nonce}'"
+ else
+ "#{directive} #{build_directive(sources, context).join(' ')}"
+ end
elsif sources
directive
else
@@ -252,27 +243,29 @@ module ActionDispatch #:nodoc:
end
end
- def build_directive(sources, request)
- sources.map { |source| resolve_source(source, request) }
+ def build_directive(sources, context)
+ sources.map { |source| resolve_source(source, context) }
end
- def resolve_source(source, request)
+ def resolve_source(source, context)
case source
when String
source
when Symbol
source.to_s
when Proc
- if request&.controller_instance.nil?
+ if context.nil?
raise RuntimeError, "Missing context for the dynamic content security policy source: #{source.inspect}"
else
- request.controller_instance.instance_exec(&source)
+ context.instance_exec(&source)
end
- when NonceGenerator
- source.call(request)
else
raise RuntimeError, "Unexpected content security policy source: #{source.inspect}"
end
end
+
+ def nonce_directive?(directive)
+ NONCE_DIRECTIVES.include?(directive)
+ end
end
end