Rails 5.2:Rails UJS、Turbolinks 和 CSP
Rails 5.2: Rails UJS, Turbolinks and CSP
我们最近将我们的应用程序升级到 Rails 5.2。我们还使用了 Turbolinks(连同 Rails 引擎)和 RailsUJS。
在 Rails 5.2 中,我们为 CSP(内容安全策略)提供了新的 DSL。在initializers/content_security_policy.rb
:
中是这样配置的
Rails.application.config.content_security_policy do |policy|
policy.object_src :none # disallow <object> tags (Good-bye Flash!)
policy.default_src :self, :https
policy.font_src :self, :https, :data, Rails.configuration.application.asset_host, Rails.configuration.application.aws_s3_media_cdn
policy.img_src :self, :https, :data, Rails.configuration.application.asset_host, Rails.configuration.application.aws_s3_media_cdn
policy.script_src :self, :https, Rails.configuration.application.asset_host
policy.style_src :self, :https, Rails.configuration.application.asset_host
if Rails.env.development? || Rails.env.test?
# Fix for webpack-dev-server and ActionCable
policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035", "ws://localhost:3000"
end
# Specify URI for violation reports
# policy.report_uri "/csp-violation-report-endpoint"
end
# If you are using UJS then enable automatic nonce generation
Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16)
这很好用。但是我无法让 Turbolinks 和 RailsUJS 一起工作。
在app/views/layouts/application.html.haml
中我们有(简化):
!!!5
%html
%head
= csrf_meta_tags
= csp_meta_tag
= javascript_pack_tag 'application', 'data-turbolinks-track': :reload
= action_cable_meta_tag
%body
= yield
假设我们有一个像这样的 ujs 按钮:
<a class="btn btn-danger" data-disable-with="Processing..." data-params="device%5Bstatus%5D=inactive" data-remote="true" rel="nofollow" data-method="patch" href="/devices/1">Shutdown</a>
还有一个看起来很简单的控制器:
class DevicesController < ApplicationController
respond_to :html
#...
def update
@device.update(device_params)
respond_with @device, location: :devices
end
end
这很好用,我们在浏览器中得到了来自 Turbolinks rails 引擎的正确响应:
Turbolinks.clearCache()
Turbolinks.visit("http://localhost:3000/devices", {"action":"replace"})
但是我们得到错误:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' https: 'nonce-QAz+FlHz5wo0IwU5sIMZ/w==' 'nonce-IsrK1b0jw1w7cqRhHeZ7ug==' 'nonce-Rpl8hMBgap79cfwdlXXwjA==' 'nonce-1Wq7MbBEYMDCkEWGexwQ9Q==' 'nonce-EUL22iiKHn0hkNuW3fpkbA==' 'nonce-F5Vg50g0JvAvkXHHu+p0qw==' 'nonce-slHxjCy9VVEvvoIcJ870lg==' 'nonce-lboTgbdLG4iCgUozIK4LPQ==' 'nonce-K9yAPOgjZDXRTvnJb3glTA==' 'nonce-ux2kfUZjU/nxJn30LaTFjQ==' 'nonce-8E8cTAX+jWNpvl5lw0Ydjw==' 'nonce-BvJ4wU3AqjZRWY930+W8kg==' 'nonce-PsS01n7AnjmiThKQJFzUBA==' 'nonce-RCoOSLXbx6Cj8aw+LuBSwA==' 'nonce-o5MfDl/crSPzjSyMzIvXNA==' 'nonce-s8NPaOETMpU2f48LR2SuqQ==' 'nonce-Omuo2P68l09PTBFxmk4DkA==' 'nonce-N3YQfaIuPSrURB8jhVz3Sw==' 'nonce-Ts4Bp4GUqawLcHI1mRLcxw==' 'nonce-fTZ6W2u9eh8K5yCJMPfJGg==' 'nonce-1ST0058rq41fDhw8CforxA==' 'nonce-tA+jUJ1x841ZseUUjvQn9w==' 'nonce-CVjBLiByDSqBNHdG6/izBA==' 'nonce-1z6mH6xtPajsxVmojM8SNA==' 'nonce-0zlDfL8I0go9aII/DGZUzg==' 'nonce-WOrw4qdxeKfZQ1R7xUfdbQ==' 'nonce-G8kmjJA5E35Asgy6mj80PQ=='". Either the 'unsafe-inline' keyword, a hash ('sha256-9KVlOPCQBe0v+kIJoBA6hi7N+aI2yVDUXS9gYk4PizU='), or a nonce ('nonce-...') is required to enable inline execution.
所以这里的第一个问题是:那么多随机数是从哪里来的?
另一项调查:在我在 javascript 控制台中调用 Turbolinks.visit 之后,csp-nonce
和 csrf-token
值正在改变。我认为这一定是问题所在。由于 Rails UJS 使用原始值将随机数添加到它创建的内联 javascript 标记中。但是在渲染完所有内容之后,nonce 发生了变化。所以内联标签不再有效。
我怎样才能避免这种情况?
--
注意:我们正在通过 webpacker 设置 Turbolinks 和 RailsUJS,如下所示:
import Turbolinks from 'turbolinks'
import Rails from 'rails-ujs'
// Start application
Rails.start(); // Rails ujs
Turbolinks.start(); // Turbolinks, obviously...
提前致谢,
温泉
您收到该错误是因为您在页面中的某处使用了内联脚本,例如:
<script>
...js
</script>
要避免此错误,您需要在 script-src
中包含 'unsafe-inline'、散列 ('sha256-...') 或随机数 ('nonce-...') CSP 指令。详情见:https://content-security-policy.com/
更好的方法是将纯脚本从页面正文中删除到单独的 javascript 文件中。
Where are those many nonces coming from?
这些随机数是由 Rails 添加的,因为您为 UJS 启用了自动随机数生成。
the csp-nonce and csrf-token values are changing
这就是他们的工作方式。如果随机数和 CSRF 令牌是静态的,那么它们就没有意义了。
跟进:
大量随机数是 rails 中的一个错误,已在 Rails 5.2.1 中得到纠正。
我们最近将我们的应用程序升级到 Rails 5.2。我们还使用了 Turbolinks(连同 Rails 引擎)和 RailsUJS。
在 Rails 5.2 中,我们为 CSP(内容安全策略)提供了新的 DSL。在initializers/content_security_policy.rb
:
Rails.application.config.content_security_policy do |policy|
policy.object_src :none # disallow <object> tags (Good-bye Flash!)
policy.default_src :self, :https
policy.font_src :self, :https, :data, Rails.configuration.application.asset_host, Rails.configuration.application.aws_s3_media_cdn
policy.img_src :self, :https, :data, Rails.configuration.application.asset_host, Rails.configuration.application.aws_s3_media_cdn
policy.script_src :self, :https, Rails.configuration.application.asset_host
policy.style_src :self, :https, Rails.configuration.application.asset_host
if Rails.env.development? || Rails.env.test?
# Fix for webpack-dev-server and ActionCable
policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035", "ws://localhost:3000"
end
# Specify URI for violation reports
# policy.report_uri "/csp-violation-report-endpoint"
end
# If you are using UJS then enable automatic nonce generation
Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16)
这很好用。但是我无法让 Turbolinks 和 RailsUJS 一起工作。
在app/views/layouts/application.html.haml
中我们有(简化):
!!!5
%html
%head
= csrf_meta_tags
= csp_meta_tag
= javascript_pack_tag 'application', 'data-turbolinks-track': :reload
= action_cable_meta_tag
%body
= yield
假设我们有一个像这样的 ujs 按钮:
<a class="btn btn-danger" data-disable-with="Processing..." data-params="device%5Bstatus%5D=inactive" data-remote="true" rel="nofollow" data-method="patch" href="/devices/1">Shutdown</a>
还有一个看起来很简单的控制器:
class DevicesController < ApplicationController
respond_to :html
#...
def update
@device.update(device_params)
respond_with @device, location: :devices
end
end
这很好用,我们在浏览器中得到了来自 Turbolinks rails 引擎的正确响应:
Turbolinks.clearCache()
Turbolinks.visit("http://localhost:3000/devices", {"action":"replace"})
但是我们得到错误:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' https: 'nonce-QAz+FlHz5wo0IwU5sIMZ/w==' 'nonce-IsrK1b0jw1w7cqRhHeZ7ug==' 'nonce-Rpl8hMBgap79cfwdlXXwjA==' 'nonce-1Wq7MbBEYMDCkEWGexwQ9Q==' 'nonce-EUL22iiKHn0hkNuW3fpkbA==' 'nonce-F5Vg50g0JvAvkXHHu+p0qw==' 'nonce-slHxjCy9VVEvvoIcJ870lg==' 'nonce-lboTgbdLG4iCgUozIK4LPQ==' 'nonce-K9yAPOgjZDXRTvnJb3glTA==' 'nonce-ux2kfUZjU/nxJn30LaTFjQ==' 'nonce-8E8cTAX+jWNpvl5lw0Ydjw==' 'nonce-BvJ4wU3AqjZRWY930+W8kg==' 'nonce-PsS01n7AnjmiThKQJFzUBA==' 'nonce-RCoOSLXbx6Cj8aw+LuBSwA==' 'nonce-o5MfDl/crSPzjSyMzIvXNA==' 'nonce-s8NPaOETMpU2f48LR2SuqQ==' 'nonce-Omuo2P68l09PTBFxmk4DkA==' 'nonce-N3YQfaIuPSrURB8jhVz3Sw==' 'nonce-Ts4Bp4GUqawLcHI1mRLcxw==' 'nonce-fTZ6W2u9eh8K5yCJMPfJGg==' 'nonce-1ST0058rq41fDhw8CforxA==' 'nonce-tA+jUJ1x841ZseUUjvQn9w==' 'nonce-CVjBLiByDSqBNHdG6/izBA==' 'nonce-1z6mH6xtPajsxVmojM8SNA==' 'nonce-0zlDfL8I0go9aII/DGZUzg==' 'nonce-WOrw4qdxeKfZQ1R7xUfdbQ==' 'nonce-G8kmjJA5E35Asgy6mj80PQ=='". Either the 'unsafe-inline' keyword, a hash ('sha256-9KVlOPCQBe0v+kIJoBA6hi7N+aI2yVDUXS9gYk4PizU='), or a nonce ('nonce-...') is required to enable inline execution.
所以这里的第一个问题是:那么多随机数是从哪里来的?
另一项调查:在我在 javascript 控制台中调用 Turbolinks.visit 之后,csp-nonce
和 csrf-token
值正在改变。我认为这一定是问题所在。由于 Rails UJS 使用原始值将随机数添加到它创建的内联 javascript 标记中。但是在渲染完所有内容之后,nonce 发生了变化。所以内联标签不再有效。
我怎样才能避免这种情况?
-- 注意:我们正在通过 webpacker 设置 Turbolinks 和 RailsUJS,如下所示:
import Turbolinks from 'turbolinks'
import Rails from 'rails-ujs'
// Start application
Rails.start(); // Rails ujs
Turbolinks.start(); // Turbolinks, obviously...
提前致谢,
温泉
您收到该错误是因为您在页面中的某处使用了内联脚本,例如:
<script>
...js
</script>
要避免此错误,您需要在 script-src
中包含 'unsafe-inline'、散列 ('sha256-...') 或随机数 ('nonce-...') CSP 指令。详情见:https://content-security-policy.com/
更好的方法是将纯脚本从页面正文中删除到单独的 javascript 文件中。
Where are those many nonces coming from?
这些随机数是由 Rails 添加的,因为您为 UJS 启用了自动随机数生成。
the csp-nonce and csrf-token values are changing
这就是他们的工作方式。如果随机数和 CSRF 令牌是静态的,那么它们就没有意义了。
跟进:
大量随机数是 rails 中的一个错误,已在 Rails 5.2.1 中得到纠正。