Политика защиты содержимого

Политика защиты содержимого (англ. Content Security Policy) автоматически применяется ко всем расширениям, разработанным с использованием WebExtension API. Она ограничивает источники, из которых расширение может загружать <script> и <object> ресурсы, и препятствует потенциально опасным практикам, например использованию eval().

Статья в краткой форме объясняет значимость этой политики, каковы её изначальные правила, как они влияют на расширение, и как расширение может изменять эти правила.

Политика защиты содержимого - это механизм, помогающий веб-сайтам предотвращать выполнение умышленно вредного кода. Веб-сайт устанавливает политику защиты, используя HTTP заголовок, посылаемый с сервера. Главным образом эта политика участвует в устанавливании допустимых источников для загрузки различного вида контента, к примеру, скриптов или встроенных плагинов. Например, веб-сайт может использовать политику защиты для инструктирования браузера, чтобы тот выполнял скрипты, загруженные только с самого сайта, а не из каких-либо других источников. Политика защиты содержимого так же может запретить браузеру использовать потенциально опасные практики, например использование eval().

Так же как веб-сайты, расширения могут загружать контент из различных источников. Например, всплывающее окно расширения определяется HTML документом, и может подключать JavaScript и CSS файлы из различных источников, точно так же, как и нормальная веб-страница:

<!DOCTYPE html>

<html>
  <head>
    <meta charset="utf-8">
  </head>

  <body>

    <!-- Некоторый HTML контент -->

    <!--
      Подключение сторонней библиотеки.
      Смотрите так же https://developer.mozilla.org/ru/docs/Web/Security/Subresource_Integrity.
    -->
    <script>
      src="https://code.jquery.com/jquery-2.2.4.js"
      integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI="
      crossorigin="anonymous">
    </script>
 
    <!-- Include my popup's own script-->
    <script src="popup.js"></script>
  </body>

</html>

В сравнении с веб-сайтами, расширения имеют доступ к дополнительному привилегированному API, так что вероятность получения к нему доступа сторонним кодом - это очень большой риск. По этой причине:

  • довольно строгая политика по защите содержимого применяются изначально. Смотрите изначальные правила по защите содержимого.
  • авторы расширений могут изменять изначальную политику, используя content_security_policy ключ в manifest.json, но даже в этом случае существуют  ограничения на возможные разрешения. Для дополнительной информации смотрите content_security_policy.

Изначальные правила по защите содержимого

Следующие правила по защите содержимого являются изначальными:

"script-src 'self'; object-src 'self';"

Они применяются к любому расширению, которое самостоятельно не указывает свою политику защиты, используя content_security_policy ключ в manifest.json. Это имеет следующие последствия:

Расположение script и object ресурсов

Используя изначальную политику защиты содержимого, вы можете загружать только локальные к расширению <script> и <object> ресурсы. Например, рассмотрите эту строку из документа расширения:

 <script src="https://code.jquery.com/jquery-2.2.4.js"></script>

Она не будет загружать запрашиваемый ресурс, и вы не сможете найти ни один ожидаемый от ресурса объект. К этой ситуации существует два решения:

  • Скачать этот ресурс, упаковать его в ваше расширение и ссылаться к нему локально.

  • Использовать ключ content_security_policy в manifest.json, чтобы позволить загрузку контента из вышеупомянутого источника..

eval() и товарищи

Изначальная политика защиты содержимого не позволяет выполнять код из JavaScript строк. Это означает, что следующие примеры кода изначально запрещены:

eval("console.log('some output');");
window.setTimeout("alert('Hello World!');", 500);
var f = new Function("console.log('foo');");

Встраиваемый (inline) JavaScript

Изначальная политика защиты содержимого не позволяет выполнять JavaScript код, встраиваемый в HTML теги. Это запрещает как выполнение JavaScript кода вложенного прямо в <script> тег, так и выполнение вписанных в атрибут обработчиков событий, означая, что следующий код так же не будет работать:

<script>console.log("foo");</script>
<div onclick="console.log('click')">Click me!</div>

Вместо того, чтобы использовать код <body onload="main()"> для запуска вашего скрипта после загрузки страницы, поставьте обработчики событий на DOMContentLoaded или load.