Rails 5.2: Rails UJS, Turbolinks и CSP - PullRequest
0 голосов
/ 04 мая 2018

Недавно мы обновили наше приложение до Rails 5.2. Мы также используем Turbolinks (вместе с Rails Engine) и RailsUJS.

С Rails 5.2 у нас появился новый DSL для CSP (Политика безопасности контента). Это настроено так в 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:

Turbolinks.clearCache()
Turbolinks.visit("http://localhost:3000/devices", {"action":"replace"})

Но мы получаем ошибку:

Отказ от выполнения встроенного сценария, поскольку он нарушает следующую директиву политики безопасности содержимого: "script-src 'self' https: 'nonce-QAz + FlHz5wo0IwU5sIMZ / w ==' 'nonce-IsrK1b0jw1w7cqRhHeZ7ug ==' nonce-RwlAxfx8 = ' '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-ТА + jUJ1x841ZseUUjvQn9w =='' nonce-CVjBLiByDSqBNHdG6 / izBA == '' nonce-1z6mH6xtPajsxVmojM8SNA == '' nonce-0zlDfL8I0go9aII / DGZUzg == '' nonce-WOrw4qdxeKf'Ud17 = G0RQ1 8kmjJA5E35Asgy6mj80PQ == '». Для включения встроенного выполнения требуется ключевое слово unsafe-inline, хеш (sha256-9KVlOPCQBe0v + kIJoBA6hi7N + aI2yVDUXS9gYk4PizU = ') или одноразовый номер (' nonce -... ') для включения встроенного выполнения.

Итак, первый вопрос здесь: откуда взялись эти многоразовые числа?

Еще одно расследование: после того, как я вызвал Turbolinks.visit в консоли javascript, значения csp-nonce и csrf-token меняются. Я думаю, что это должно быть проблемой. Поскольку Rails UJS использует исходное значение, чтобы добавить nonce во встроенный тег javascript, который он создает. Но после того, как все оказано, одноразовый номер изменился Таким образом, встроенный тег больше не действителен. Как я могу избежать этого?

- ПРИМЕЧАНИЕ. Мы настраиваем Turbolinks и RailsUJS через веб-упаковщик следующим образом:

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

Заранее спасибо,
спа

Ответы [ 2 ]

0 голосов
/ 13 августа 2018

Продолжение:

Множество одноразовых номеров было ошибкой в ​​рельсах, которая была исправлена ​​в Rails 5.2.1.

0 голосов
/ 04 мая 2018

Вы получаете эту ошибку, потому что где-то на странице вы используете встроенный скрипт, например:

<script>
  ...js
</script>

Чтобы избежать этой ошибки, вам нужно либо включить unsafe-inline, хэш ('sha256 -...'), либо nonce ('nonce -...') в свой script-src Директива CSP. Подробнее см .: https://content -security-policy.com /

Еще лучше, просто удалите простой текст из тела страницы в отдельный файл javascript.

Откуда взялись эти одноразовые числа?

Эти одноразовые номера добавлены Rails, потому что вы включили автоматическую генерацию одноразовых номеров для UJS.

значения csp-nonce и csrf-token меняются

Вот как они работают. Если бы одноразовые номера и токены CSRF были статическими, в них не было бы смысла.

...