Как получить JavaScript с сервера, отследить ход загрузки и не использовать unsafe-eval в Content-Security-Policy? - PullRequest
4 голосов
/ 29 февраля 2020

У меня тяжелый JavaScript файл на сервере (> 3 МБ). Я хочу быстро загрузить страницу и показать пользователю индикатор выполнения загрузки. В настоящее время я использую fetch и WritableStream для загрузки данных и отслеживания процесса загрузки как:

let resource = await fetch('heavy_file.js')
resource.clone().body.pipeTo(new WritableStream({
    write(t) { on_receive(t.length) }
}))

И затем я использую Функция для оценки. Это имеет несколько проблем. Как я могу:

  • Загрузить скрипт, предпочтительно используя fetch (я использую тот же метод для загрузки файлов WASM, я также хочу отслеживать ход их загрузки и WebSsembly .compileStreaming API требует использования fetch).
  • Отслеживание хода загрузки таким образом, чтобы это работало в современных браузерах.
  • Возможность использования этого решения без включения script-src 'unsafe-eval' in Content-Security-Policy ?

PS. Конечно, в настоящее время нам нужно использовать script-src 'wasm-eval' в Chrome при загрузке файлов WASM, пока ошибка не будет исправлена.

Ответы [ 2 ]

1 голос
/ 01 мая 2020

Рассмотрите возможность использования Service Worker для перехвата определенных запросов и отслеживания общего прогресса загрузки всех ваших активов. ПО может затем использовать postMessage() и отправлять обновления прогресса на вашу страницу. Этот пример процесса загрузки Service Worker может быть расширен для поддержки нескольких файлов (включая файлы WASM): https://fetch-progress.anthum.com/sw-basic/

0 голосов
/ 12 марта 2020

Опция 1

Если вы можете заранее вычислить га sh скрипта, который вы загружаете (если это не что-то, генерируемое динамически), тогда простой способ избежать

включение script-sr c unsafe-eval в Content-Security-Policy

означает добавление в CSP только ха sh этого указанного c сценария заголовок - это по-прежнему гарантирует, что вы не выполняете никакого ненадежного кода, и в то же время позволяет загружать и выполнять сценарий вручную.

В MDN есть еще несколько примеров реализации таких политик CSP здесь .

Что касается самой загрузки, у вас есть два разных пути отсюда:

Опция 1.1

Объедините ha sh с политикой CSP3 unsafe-hashes, которая позволит вам продолжать использовать Function или eval, как вы в настоящее время, но при этом ограничивать код только доверенным.

Например, если у вас есть скрипт типа

alert('Hello, world.');

, тогда ваш заголовок CSP должен содержать

Content-Security-Policy: script-src 'unsafe-hashes' 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='

К сожалению, CSP lev el 3, или, по крайней мере, эта опция поддерживается только в Chromium на момент написания.

Option 1.2

Вместо использования Function или eval, вы можете динамически создать тег сценария из JavaScript, заполнить его textContent содержимым вашего ответа и вставить его в DOM:

let resource = await fetch('heavy_file.js')
resource.clone().body.pipeTo(new WritableStream({
    write(t) { on_receive(t.length) }
}));
resource.text().then(res => {
  let s = document.createElement('script');
  s.textContent = res;
  document.head.appendChild(s);
});

В этом случае вам нужно только добавить ха sh сценария для CSP, и он будет работать во всех браузерах:

Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG-HiZ1guq6ZZDob_Tng='

Вариант 2

Если вы хотите поддерживать динамически генерируемые сценарии, тогда единственным вариантом может быть переместите свой код отслеживания прогресса в Service Worker, а затем используйте Client.postMessage, чтобы сообщить о ходе выполнения сценарию на странице.

Это будет работать для любого контента, полученного из вашего источника, но только после установки Service Worker - обычно при последующей загрузке страницы, что может не помочь вам, если загружаемый вами большой скрипт является частью страницы, которую пользователь сначала посещает на вашем сайте.

...