Поделиться через


Использование политики безопасности содержимого (CSP) для управления ресурсами, которые можно запускать

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

{
    ...,
    "content_security_policy": "[policy string]"
    ...
}

Например, ниже приведена политика безопасности содержимого по умолчанию, как описано ниже в разделе Ограничения политики по умолчанию:

{
    ...,
    "content_security_policy": "script-src 'self'; object-src 'self'; worker-src 'self'"
    ...
}

Чтобы устранить большой класс потенциальных проблем с межсайтовых сценариев, система расширений Microsoft Edge включает политику безопасности содержимого (CSP). CSP вводит некоторые строгие политики, которые по умолчанию делают расширения более безопасными, и предоставляет возможность создавать и применять правила, регулирующие типы содержимого, которое может загружаться и запускаться расширениями и приложениями.

Как правило, CSP работает как механизм блокировки или списка разрешений для ресурсов, загруженных или запущенных расширением. Определение разумной политики для расширения позволяет вам тщательно изучить ресурсы, необходимые вашему расширению, и попросить браузер убедиться, что это единственные ресурсы, к которым у вашего расширения есть доступ. Политики обеспечивают безопасность над разрешениями узла, которые вы запрашиваете расширение; они являются дополнительным уровнем защиты, а не заменой.

В отличие от этого, на веб-странице такая политика определяется с помощью заголовка HTTP или элемента meta . Но в системе расширения Microsoft Edge заголовок HTTP или meta элемент не являются подходящим механизмом.

См. следующие статьи:

Ограничения политики по умолчанию

Пакеты, которые не определяют manifest_version , не имеют политики безопасности содержимого по умолчанию.

Пакеты, использующие manifest_version , имеют следующую политику безопасности содержимого по умолчанию:

script-src 'self'; object-src 'self'; worker-src 'self'

Политика добавляет безопасность, ограничивая расширения и приложения тремя способами:

Код, подобный следующему, не работает:

alert(eval("foo.bar.baz"));
window.setTimeout("alert('hi')", 10);
window.setInterval("alert('hi')", 10);
new Function("return foo.bar.baz");

Оценка строк JavaScript, как это, является общим вектором атаки XSS. Вместо этого следует написать следующий код:

alert(foo && foo.bar && foo.bar.baz);
window.setTimeout(function() { alert('hi'); }, 10);
window.setInterval(function() { alert('hi'); }, 10);
function() { return foo && foo.bar && foo.bar.baz };

Встроенные коды JavaScript не выполняются

Встроенный Код JavaScript не выполняется. Это ограничение запрещает как встроенные <script> блоки, так и встроенные обработчики событий, такие как <button onclick="...">.

Первое ограничение уничтожает огромный класс атак на межсайтовые скрипты, что делает невозможным случайное выполнение скрипта, предоставленного вредоносным сторонним поставщиком. Однако для этого требуется написать код с чистым разделением между содержимым и поведением. Пример может сделать это более понятным. Вы можете попытаться написать всплывающее окно действия браузера в виде одного pop-up.html из следующих элементов:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script>
            function awesome() {
                // do something awesome!
            }

            function totallyAwesome() {
                // do something TOTALLY awesome!
            }

            function clickHandler(element) {
                setTimeout("awesome(); totallyAwesome()", 1000);
            }

            function main() {
                // Initialization work goes here.
            }
        </script>
    </head>
    <body onload="main();">
        <button onclick="clickHandler(this)">
            Click for awesomeness!
        </button>
    </body>
</html>

Но три вещи должны измениться, чтобы сделать эту работу так, как вы ожидаете:

  • Определение clickHandler должно быть перемещено во внешний файл JavaScript (popup.js может быть хорошим целевым объектом).

  • Определения встроенных обработчиков событий должны быть перезаписаны с точки зрения и извлечены addEventListener в popup.js. Если в настоящее время вы запускаете программу с помощью кода, например <body onload="main();">, попробуйте заменить его, подключив DOMContentLoaded к событию документа или load событию окна в зависимости от ваших требований. Используйте первый, так как он обычно активируется быстрее.

  • Вызов setTimeout необходимо переписать, чтобы избежать преобразования строки "awesome(); totallyAwesome()" в JavaScript для запуска.

Эти изменения могут выглядеть примерно так:

function awesome() {
    // Do something awesome!
}

function totallyAwesome() {
    // do something TOTALLY awesome!
}

function awesomeTask() {
    awesome();
    totallyAwesome();
}

function clickHandler(e) {
    setTimeout(awesomeTask, 1000);
}

function main() {
    // Initialization work goes here.
}

// Add event listeners once the DOM has fully loaded by listening for the
// `DOMContentLoaded` event on the document, and adding your listeners to
// specific elements when it triggers.
document.addEventListener('DOMContentLoaded', function () {
    document.querySelector('button').addEventListener('click', clickHandler);
    main();
});
<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="popup.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

Загружаются только локальные ресурсы скриптов и объектов.

Ресурсы скриптов и объектов можно загрузить только из пакета расширения, а не из Интернета в целом. Это гарантирует, что расширение выполняет только код, который вы специально утвердили, что не позволит активному сетевому злоумышленнику злонамеренно перенаправить запрос на ресурс.

Вместо написания кода, который зависит от загрузки jQuery (или любой другой библиотеки) из внешнего CDN, рассмотрите возможность включения конкретной версии jQuery в пакет расширения. То есть, вместо:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

Вместо этого используйте следующий подход. Скачайте файл, добавьте его в пакет и напишите:

<!doctype html>
<html>
    <head>
        <title>My Awesome Pop-up!</title>
        <script src="jquery.min.js"></script>
    </head>
    <body>
        <button>Click for awesomeness!</button>
    </body>
</html>

Отмена политики по умолчанию

Можно разрешить выполнение следующих типов скриптов:

Подробные сведения приведены ниже.

Встроенный скрипт

Встроенные скрипты можно разрешить, указав в политике хэш исходного кода в кодировке Base64. Этот хэш должен быть префиксирован используемым хэш-алгоритмом (sha256, sha384 или sha512). Пример см. в разделе Использование хэша W3C > для <элементов скрипта>.

Удаленный скрипт

Если требуются некоторые внешние ресурсы JavaScript или объектов, вы можете смягчить политику в ограниченной степени, указав список безопасных источников, из которых должны приниматься скрипты. Убедитесь, что ресурсы среды выполнения, загруженные с повышенными разрешениями расширения, являются именно ожидаемыми ресурсами и не заменяются активным сетевым злоумышленником. Так как атаки "человек в середине " являются тривиальными и неопределяемыми по ПРОТОКОЛу HTTP, эти источники не принимаются.

В настоящее время можно разрешить список источников со следующими схемами: blob, filesystem, httpsи extension. Ведущая часть источника должна быть явно указана https для схем и extension . Универсальные подстановочные знаки, такие как https:, https://* и https://*.com не допускаются; поддоменовые знаки, такие как, https://*.example.com разрешены. Домены в списке Общедоступный суффикс также рассматриваются как универсальные домены верхнего уровня. Чтобы загрузить ресурс из этих доменов, должен быть явно указан поддомен. Например, https://*.cloudfront.net является недопустимым, но https://XXXX.cloudfront.net и https://*.XXXX.cloudfront.net может иметь значение allowlisted.

Для упрощения разработки ресурсы, загруженные по протоколу HTTP с серверов на локальном компьютере, могут иметь значение allowlisted. Можно разрешить список источников скриптов и объектов на любом порту http://127.0.0.1 или http://localhost.

Примечание.

Ограничение на ресурсы, загруженные по протоколу HTTP, применяется только к тем ресурсам, которые выполняются напрямую. Вы по-прежнему можете, например, устанавливать XMLHTTPRequest подключения к любому источнику; политика по умолчанию не ограничивает connect-src ни одну из других директив CSP каким-либо образом.

Неопубликованное определение политики, которое позволяет загружать ресурсы скриптов по example.com протоколу HTTPS, может выглядеть следующим образом:

"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"

Примечание.

И script-src , и object-src определяются политикой. Microsoft Edge не принимает политику, которая не ограничивает каждое из этих значений (по крайней мере) "self".

Оцененный JavaScript

Политику в отношении eval() и связанных функций, таких как setTimeout(String), setInterval(String)и new Function(String) , можно смягчить, добавив unsafe-eval в политику:

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

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

Ужесточение политики по умолчанию

Вы можете ужесточить эту политику в любой степени, в которой позволяет расширение, чтобы повысить безопасность, за счет удобства. Чтобы указать, что расширение может загружать только ресурсы любого типа (образы и т. д.) из связанного default-src 'self' пакета расширения, например, может быть уместна политика .

Скрипты содержимого

Обсуждаемая политика применяется к фоновым страницам и страницам событий расширения. То, как скрипты содержимого применяются к скриптам содержимого расширения, сложнее.

Скрипты содержимого, как правило, не подчиняются CSP расширения. Так как скрипты содержимого не являются HTML, main влияние этого заключается в том, что они могут использоватьeval, даже если CSP расширения не указывает unsafe-eval, хотя это не рекомендуется. Кроме того, CSP страницы не применяется к сценариям содержимого. Более сложными являются <script> теги, которые скрипты содержимого создают и помещают в DOM страницы, на которую они выполняются. На них ссылаются как на внедренные в DOM скрипты в будущем.

Скрипты, внедренные в DOM, которые выполняются сразу после внедрения на страницу, выполняются должным образом. Представьте себе скрипт содержимого со следующим кодом в качестве простого примера:

document.write("<script>alert(1);</script>");

Этот скрипт содержимого вызывает исключение alert сразу после document.write(). Обратите внимание, что этот параметр выполняется независимо от политики, указанной страницей. Однако поведение становится более сложным как внутри внедренного скрипта DOM, так и для любого скрипта, который не запускается сразу после внедрения.

Представьте, что расширение выполняется на странице, предоставляющей связанный поставщик служб CSP, указывающий script-src 'self'. Теперь представьте, что скрипт содержимого выполняет следующий код:

document.write("<button onclick='alert(1);'>click me</button>'");

Если пользователь нажимает на нее onclick , скрипт не выполняется. Это связано с тем, что скрипт не был запущен сразу, а код, который не интерпретируется до click возникновения события, не считается частью скрипта содержимого, поэтому CSP страницы (не расширения) ограничивает поведение. А так как этот поставщик CSP не указывает unsafe-inline, встроенный обработчик событий блокируется.

Правильный способ реализации требуемого поведения в этом случае — добавить onclick обработчик в качестве функции из скрипта содержимого следующим образом:

document.write("<button id='mybutton'>click me</button>'");
var button = document.getElementById('mybutton');
button.onclick = function() {
      alert(1);
};

Другая аналогичная проблема возникает, если скрипт содержимого выполняет следующее:

var script = document.createElement('script');
script.innerHTML = 'alert(1);'
document.getElementById('body').appendChild(script);

В этом случае выполняется скрипт, и появится оповещение. Однако рассмотрим следующий случай:

var script = document.createElement('script');
script.innerHTML = 'eval("alert(1);")';
=document.getElementById('body').appendChild(script);

Во время выполнения исходного скрипта вызов eval блокируется. То есть, хотя начальная среда выполнения скрипта разрешена, поведение в скрипте регулируется CSP страницы. Таким образом, в зависимости от того, как вы пишете скрипты, внедренные DOM в расширение, изменения В CSP страницы могут повлиять на поведение расширения.

Так как CSP страницы не влияет на сценарии содержимого, это отличная причина, чтобы включить в скрипт содержимого максимально возможное поведение вашего расширения, а не внедренные скрипты DOM.

См. также

Примечание.

Части этой страницы являются изменениями, основанными на работе, созданной и совместно используемой Google и используемой в соответствии с условиями, описанными в международной лицензии Creative Commons Attribution 4.0. Исходная страница находится здесь.

Creative Commons License Эта работа лицензируется по международной лицензии Creative Commons Attribution 4.0.