Загрузка скриптов ‘self’ заблокирована, но когда я использую одноразовый номер, они работают?

#javascript #ajax #content-security-policy #nonce

#javascript #ajax #content-security-policy #одноразовый номер

Вопрос:

Вероятно, есть простое решение для этого, но я не могу его понять.

У меня CSP определен следующим образом:

 "Content-Security-Policy: default-src * 'unsafe-inline' 'unsafe-eval' data: blob:; style-src 'unsafe-inline' 'self' cdnjs.cloudflare.com fonts.googleapis.com; script-src www.google-analytics.com cdnjs.cloudflare.com 'self' 'nonce-". $_SESSION['nonce'] . "'; img-src * 'self' data:;object-src 'self' sias.dev:8000; connect-src * 'unsafe-inline'; frame-src 'self' sias.dev:8000 www.google.com;"
  

CSP нуждается в небольшой настройке, но частично работает. Мне нужен одноразовый номер, потому что у меня есть несколько устаревших сайтов, на которых есть встроенные скрипты. Одноразовый номер генерируется динамически и изменяется при загрузке страницы. Однако я столкнулся с проблемой, когда я загружаю некоторые скрипты «self» на страницу, вызываемую через AJAX (не встроенные, а теги script src. Вероятно, это плохая практика, но я не хочу загружать их, кроме страницы, вызываемой через ajax.

Странно то, что у меня нет встроенных скриптов на этой странице, только теги script src, как показано ниже, где одноразовый номер является динамическим и соответствует политике CSP.

 <script nonce = "" src="/js/create_dicom/js/plupload.full.min.js"></script>
<script nonce = "" src="/js/create_dicom/js/jquery.ui.plupload.min.js"></script>
<script nonce = "" src="/js/create_dicom/js/main.js"></script>
<script nonce = "" src="/bower/pdfjs/src/pdf.js"></script>
<script nonce = "" src="/bower/pdfjs/src/pdf.worker.js"></script>
  

Когда я не использую одноразовый номер, я получаю:

 "Content Security Policy: The page’s settings blocked the loading of a resource at inline (“script-src”)."
  

Когда я использую одноразовый номер, они загружаются нормально, и страница работает. Я думал, что вам нужен только одноразовый номер для встроенных скриптов, а не для «собственного» скрипта. Должен ли я каким-то образом использовать strict-dynamic? Мне не нужен одноразовый номер на главной странице для тегов script-src. Они там нормально загружаются?

Кроме того, места, в которых мне нужен одноразовый номер, в основном находятся на страницах, которые загружаются через AJAX. Есть ли способ реорганизовать вещи (т. Е. Поместить их в файлы .js и таким образом загрузить соответствующий файл .js). Это своего рода проблема, потому что у меня нет загрузчика скриптов, и я бы хотел загрузить только соответствующий js для файлов, загружаемых через AJAX.

Спасибо.

Ответ №1:

  1. Ошибка консоли: The page’s settings blocked the loading of a resource at INLINE тогда у вас определенно заблокирован встроенный скрипт, а не внешний, поэтому он не имеет ничего общего с ‘self’. Вы можете посмотреть в правый угол консоли и увидеть script_name:line_number: столбец, в котором это происходит.
    В случае внешнего скрипта блокировки ошибка выглядит следующим образом: The page’s settings blocked the loading of a resource at HTTPS://EXAMPLE.COM/PATH/SCRIPT.JS .

  2. Может быть 3 вида встроенных скриптов: <script>...<script> , <a href='javascript:void(0)' и <a onclick='evtHandler()' . Firefox не различает их, Chrome более подробный, поэтому посмотрите, как выглядит эта ошибка в браузере Chrome.
    Есть 2 варианта:
    - в Chrome НЕТ ошибок — это хорошо, FF известен ложными срабатываниями
    - в Chrome есть ошибка — у вас есть встроенный скрипт, и Chrome скажет, какой именно.

  3. Настройка CSP через журнал консоли браузера — плохая практика. Вы используете pdf.min.js , но этот скрипт содержит фрагмент кода:

const n = document.createElement("script");
n.src = e;
n.onload = t;
n.onerror = function() {
r(new Error("Cannot load script at: " n.src))
};
(document.head || document.documentElement).appendChild(n)

это означает, что некоторые внешние скрипты могут быть загружены при некоторых условиях. Только Бог знает, что вам нужно нажать, чтобы это произошло, и откуда будет загружен этот скрипт.
Поэтому правильный способ (если на сайте есть посетители) — использовать report-uri директиву и анализировать отчеты о нарушениях в течение примерно 2 недель.

PS: Просто любопытно — вы указываете: connect-src * 'unsafe-inline'; так у вас где-то есть встроенные скрипты? Кстати, токен ‘unsafe-inline’ не используется в connect-src директиве, он будет проигнорирован.

Комментарии:

1. Спасибо. Ошибка с подключением-src. Я могу просто медленно реорганизовать код, чтобы мне не нужны одноразовые номера. На данный момент в основном работают, но у меня есть проблема при использовании нескольких вкладок, потому что при каждой загрузке страницы генерируется новый одноразовый номер, поэтому у 2 вкладок будут разные одноразовые номера, и запросы AJAX тогда не работают. Если я использую один одноразовый номер за сеанс, это не проблема, но это когда они генерируются при каждой загрузке страницы. Возможно, придется просто провести рефакторинг, чтобы это не было проблемой.

2. Если вы не меняете код между <script>...</script> ними часто, токен ‘sha256-value’ будет полезен: developer.mozilla.org/en-US/docs/Web/HTTP/Headers/… . Он автоматически разрешает встроенный скрипт, если его хэш представлен в директиве script-src. Браузер Chrome автоматически вычисляет хэши для всех заблокированных встроенных скриптов, просто загляните в консоль : Either the 'unsafe-inline' keyword, a hash ('sha256-RealHashIsHere'), or a nonce ('nonce -...') is required to enable inline execution . И вы можете использовать и ‘sha25-value’ и ‘одноразовое значение’ одновременно.

3. Работает в любом случае. Скрипты в основном статичны, поэтому использование хэша — это ленивый способ избежать помещения их в отдельные файлы .js. В итоге у меня было бы довольно много хэшей для добавления в мой CSP. Это проблема с производительностью или существует ограниченный общий размер заголовков (по-видимому, 4-8 КБ! никогда бы не приблизился к этому).