@@ -157,8 +157,7 @@ def js_snippet
157157 def script_tag ( content , env )
158158 if ( nonce = rails5_nonce ( env ) )
159159 script_tag_content = "\n <script type=\" text/javascript\" nonce=\" #{ nonce } \" >#{ content } </script>"
160- elsif secure_headers_nonce?
161- nonce = ::SecureHeaders . content_security_policy_script_nonce ( ::Rack ::Request . new ( env ) )
160+ elsif ( nonce = secure_headers_nonce ( env ) )
162161 script_tag_content = "\n <script type=\" text/javascript\" nonce=\" #{ nonce } \" >#{ content } </script>"
163162 else
164163 script_tag_content = "\n <script type=\" text/javascript\" >#{ content } </script>"
@@ -172,28 +171,40 @@ def html_safe_if_needed(string)
172171 string
173172 end
174173
175- # Rails 5.2 Secure Content Policy
174+ # Rails 5.2+ Secure Content Policy
176175 def rails5_nonce ( env )
177- # The nonce is the preferred method, however 'unsafe-inline' is also possible.
178- # The app gets to decide, so we handle both. If the script_src key is missing,
179- # Rails will not add the nonce to the headers, so we should not add it either.
180- # If the 'unsafe-inline' value is present, the app should not add a nonce and
181- # we should ignore it if they do.
182- req = ::ActionDispatch ::Request . new env
176+ req = ::ActionDispatch ::Request . new ( env )
177+
178+ # Rails will only return a nonce if the app has set a nonce generator.
179+ # So if we get a valid nonce here, we know we should use it.
180+ #
181+ # Having both 'unsafe-inline' and a nonce is a valid and preferred
182+ # browser compatibility configuration.
183+ #
184+ # If the script_src key is missing, Rails will not add the nonce to the headers,
185+ # so we detect this and will not add it in this case.
183186 req . respond_to? ( :content_security_policy ) &&
184187 req . content_security_policy &&
185188 req . content_security_policy . directives [ 'script-src' ] &&
186189 req . content_security_policy_nonce
187190 end
188191
189192 # Secure Headers gem
190- def secure_headers_nonce?
191- secure_headers . append_nonce?
193+ def secure_headers_nonce ( env )
194+ req = ::Rack ::Request . new ( env )
195+
196+ return unless secure_headers ( req ) . append_nonce?
197+
198+ ::SecureHeaders . content_security_policy_script_nonce ( req )
192199 end
193200
194- def secure_headers
201+ def secure_headers ( req )
195202 return SecureHeadersFalse . new unless defined? ( ::SecureHeaders ::Configuration )
196203
204+ # If the nonce key has been set, the app is using nonces for this request.
205+ # If it hasn't, we shouldn't cause one to be added to script_src, so return now.
206+ return SecureHeadersFalse . new unless secure_headers_nonce_key ( req )
207+
197208 config = ::SecureHeaders ::Configuration
198209
199210 secure_headers_cls = nil
@@ -211,6 +222,10 @@ def secure_headers
211222 secure_headers_cls . new
212223 end
213224
225+ def secure_headers_nonce_key ( req )
226+ defined? ( ::SecureHeaders ::NONCE_KEY ) && req . env [ ::SecureHeaders ::NONCE_KEY ]
227+ end
228+
214229 class SecureHeadersResolver
215230 def append_nonce?
216231 csp_needs_nonce? ( find_csp )
0 commit comments