【问题标题】:Rails 5.2: Rails UJS, Turbolinks and CSPRails 5.2:Rails UJS、Turbolinks 和 CSP
【发布时间】:2018-10-14 21:53:51
【问题描述】:

我们最近将应用程序升级到 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"})

但是我们得到了错误:

拒绝执行内联脚本,因为它违反了以下内容安全策略指令:“script-src 'self' https: 'nonce-QAz+FlHz5wo0IwU5sIMZ/w==' 'nonce-IsrK1b0jw1w7cqRhHeZ7ug==' 'nonce-Rpl8hMBgap79cfwdlXXwjA= = ' '随机数-1Wq7MbBEYMDCkEWGexwQ9Q ==' '随机数-EUL22iiKHn0hkNuW3fpkbA ==' '随机数-F5Vg50g0JvAvkXHHu + p0qw ==' '随机数-slHxjCy9VVEvvoIcJ870lg ==' '随机数-lboTgbdLG4iCgUozIK4LPQ ==' '随机数-K9yAPOgjZDXRTvnJb3glTA =='' 随机数-ux2kfUZjU / nxjn30latfjq =='''nonce-8e8ctax + jwnpvl5lw0ydjw ==''once-bvj4wu3aqjzrwy930 + w8kg ==''nonce-pss01n7aanjmithkqjfzuba ==''nonce-rcooslxbx6cj8aw + lubswa ==''nonce-o5mfdl / crspzjsymzivxna ==''''''nonce -s8NPaOETMpU2f48LR2SuqQ == ' '随机数-Omuo2P68l09PTBFxmk4DkA ==' '随机数-N3YQfaIuPSrURB8jhVz3Sw ==' '随机数-Ts4Bp4GUqawLcHI1mRLcxw ==' '随机数-fTZ6W2u9eh8K5yCJMPfJGg ==' '随机数-1ST0058rq41fDhw8CforxA ==' '随机数-TA + jUJ1x841ZseUUjvQn9w =='' nonce-CVjBLiByDSqBNHdG6/izBA==''nonce-1z6mH6xtPajsxVmojM8SNA==''nonce-0zlDfL8I0go9aII/DGZUzg==''nonce-WOrw4qdxeKfZQ1R7xUfdbQ==''nonce-G8km jJA5E35Asgy6mj80PQ=='"。要启用内联执行,需要使用“unsafe-inline”关键字、哈希(“sha256-9KVlOPCQBe0v+kIJoBA6hi7N+aI2yVDUXS9gYk4PizU=”)或随机数(“nonce-...”)。

所以这里的第一个问题:这么多随机数是从哪里来的?

另一项调查:我在 JavaScript 控制台中调用 Turbolinks.visit 后,csp-noncecsrf-token 值正在发生变化。我认为这一定是问题所在。由于 Rails UJS 使用原始值将 nonce 添加到它创建的内联 javascript 标记中。但是在一切都被渲染之后,随机数发生了变化。所以内联标签不再有效。 我怎样才能避免这种情况?

-- 注意:我们正在通过 webpacker 设置 Turbolinks 和 RailsUJS,如下所示:

import Turbolinks from 'turbolinks'
import Rails from 'rails-ujs'
// Start application
Rails.start(); // Rails ujs
Turbolinks.start(); // Turbolinks, obviously...

提前致谢,
温泉

【问题讨论】:

  • 你是通过 webpacker 添加 Rails-UJS 吗?

标签: ruby-on-rails content-security-policy turbolinks rails-ujs


【解决方案1】:

跟进:

大量随机数是 Rails 中的一个错误,已在 Rails 5.2.1 中得到纠正。

【讨论】:

  • 这确实解决了我的问题。谢谢你的提示!
【解决方案2】:

您收到该错误是因为您在页面的某处使用了内联脚本,例如:

<script>
  ...js
</script>

要避免此错误,您需要在 script-src 中包含“unsafe-inline”、哈希(“sha256-...”)或随机数(“nonce-...”) CSP 指令。详情见:https://content-security-policy.com/

更好的是,只需将纯脚本从页面正文中删除到单独的 javascript 文件中。

这么多随机数是从哪里来的?

这些 nonce 是由 Rails 添加的,因为您为 UJS 启用了自动 nonce 生成。

csp-nonce 和 csrf-token 值正在改变

这就是他们的工作方式。如果 nonces 和 CSRF 令牌是静态的,那么它们将毫无意义。

【讨论】:

  • 很遗憾没有。我的应用程序中没有任何内联脚本。只有谷歌标签管理器。但它是用javascript_tag nonce: true 插入的,并在开发中被禁用。我知道随机数必须改变。但不是在 ujs 请求中。如果我使用调试器,我会看到从 rails-ujs 注入的内联脚本具有旧的随机数。但脑袋反应过来后又换了一个。所以它是无效的。这就是问题所在。
  • 该错误清楚地表明您的源代码中有一个内联脚本。也许您正在通过其他脚本动态插入它?