Подтвердить что ты не робот

Chrome 18+: как разрешить встроенные скрипты с политикой безопасности контента?

Chrome 18 Dev/Canary только что был выпущен, и content_security_policy потребуется в манифесте для определенных расширений.

Я пытаюсь заставить CSP работать для встроенных скриптов, но я не знаю, что я делаю что-то неправильно или это ошибка Chrome 18.

manifest.json:

{
    "name": "CSP Test",
    "version": "1.0",
    "manifest_version": 2,
    "options_page": "test.html",
    "content_security_policy": "default-src 'unsafe-inline'"
}

test.html:

<html><head>
<script type="text/javascript">
        alert("hello");
</script>
</head></html>

В Chrome 18 это распакованное расширение не загружается, отображая сообщение об ошибке:

Could not load extension from '[extension directory]'. Invalid value for 'content_security_policy'.

Если я изменил значение 'unsafe-inline' на 'self', расширение загрузилось нормально, но alert() не работает, а консоль страницы параметров содержит ошибку:

Отказано в выполнении встроенного script из-за политики безопасности контента.

В Chrome 16, используя 'unsafe-inline', добавляет прекрасную нагрузку и alert(). Однако в Chrome 16 замена 'unsafe-inline' на 'foo' позволяет загружать расширение, но, конечно же, не позволяет alert() работать, поэтому, возможно, Chrome 18 более строг, чем 16, но...

Является ли default-src 'unsafe-inline' фактически недействительным, или это ошибка? Какое значение CSP можно использовать для работы alert() в Chrome 18?


В соответствии с принятым ответом ниже встроенные скрипты больше не работают в расширениях в Chrome 18. alert() необходимо поместить в свой собственный файл JavaScript.

4b9b3361

Ответ 1

Для последних версий Chrome (46+) текущий ответ больше недействителен. unsafe-inline по-прежнему не имеет эффекта (в тегах заголовка манифеста и в meta), но в документации вы можете использовать описанную технику здесь, чтобы уменьшить ограничение.

Использование хешей для элементов <script>

Директива script-src позволяет разработчикам присваивать белый список конкретному встроенному script, указывая его хэш как разрешенный источник script.

Использование прост. Сервер вычисляет хэш конкретного содержимого блоков script и включает в себя кодировку base64 этого значения в заголовке Content-Security-Policy:

Content-Security-Policy: default-src 'self';
                     script-src 'self' https://example.com 'sha256-base64 encoded hash'

Пример

Рассмотрим следующее:

manifest.json:

{
  "manifest_version": 2,
  "name": "csp test",
  "version": "1.0.0",
  "minimum_chrome_version": "46",
  "content_security_policy": "script-src 'self' 'sha256-WOdSzz11/3cpqOdrm89LBL2UPwEU9EhbDtMy2OciEhs='",
  "background": {
    "page": "background.html"
  }
}

background.html:

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <script>alert('foo');</script>
  </body>
</html>

Результат:
диалоговое окно предупреждения из встроенного  script

Дальнейшие исследования

Я также тестировал установку применимой директивы в теге meta вместо манифеста. Хотя CSP, указанный в сообщении консоли, включал содержимое тега, он не выполнил встроенный script (в Chrome 53).

новый background.html:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-WOdSzz11/3cpqOdrm89LBL2UPwEU9EhbDtMy2OciEhs='">
  </head>
  <body>
    <script>alert('foo');</script>
  </body>
</html>

Результат:
сообщения об ошибках консоли о политике безопасности содержимого

Приложение: Генерация хэшей

Вот два метода генерации хэшей:

  • Python (передайте JS на stdin, пропустите его где-нибудь еще):
import hashlib
import base64
import sys

def hash(s):
    hash = hashlib.sha256(s.encode()).digest()
    encoded = base64.b64encode(hash)
    return encoded

contents = sys.stdin.read()
print(hash(contents))
  1. В JS, используя Crypto Library в Стэнфорде Javascript:
var sjcl = require('sjcl');
// Generate base64-encoded SHA256 for given string.
function hash(s) {
  var hashed = sjcl.hash.sha256.hash(s);
  return sjcl.codec.base64.fromBits(hashed);
}

Убедитесь, что при хэшировании встроенных скриптов содержимое целиком тега script включено (включая все ведущие/завершающие пробелы). Если вы хотите включить это в свои сборки, вы можете использовать что-то вроде cheerio, чтобы получить соответствующие разделы. В общем случае для любого html вы можете:

var $ = cheerio.load(html);
var csp_hashes = $('script')
  .map((i, el) => hash($(el).text())
  .toArray()
  .map(h => `'sha256-${h}'`)
  .join(' ');
var content_security_policy = `script-src 'self' 'unsafe-eval' ${csp_hashes}; object-src 'self'`;

Это метод, используемый в hash-csp, плагин gulp для генерации хэшей.

Ответ 2

Следующий ответ верен для более старых версий Chrome (< 46). Для более поздних, пожалуйста, проверьте @Chris-Hunt ответ fooobar.com/questions/258274/...

Я только что опубликовал очень похожий ответ на вопрос fooobar.com/questions/258275/...

Как сказано, нет возможности ослабить встроенную политику безопасности в расширениях v2. unsafe-inline просто не работает, намеренно.

Нет другого пути, кроме перемещения всего javascript в js файлы и указания на них с помощью <script src>.

Однако существует возможность делать Eval и новую функцию внутри изолированного iframe, например, со следующими строками в манифесте:

"sandbox": {
    "pages": [
      "page1.html",
      "directory/page2.html"
    ]
},

Страница с песочницей не будет иметь доступа к API расширения или приложения или к прямому доступу к страницам, отличным от песочницы (он может связываться с ними через postMessage()). Вы также можете ограничить права на песочницу специальным CSP

Теперь есть полный пример из команды Google Chrome в github eval в iframe о том, как обойти проблему, обмениваясь с изолированной песочницей iframe, а также краткое руководство по аналитике

Спасибо Google, там много переписывания расширений в линейке: (

ИЗМЕНИТЬ

Можно устранить политику безопасности для REMOTE-скриптов. Но не для строк.

Политика против eval() и ее родственников, таких как setTimeout(String), setInterval(String) и new Function(String), можно смягчить, добавив 'unsafe-eval' в свою политику: "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"

Однако мы настоятельно рекомендуем не делать этого. Эти функции являются печально известными векторами атаки XSS.

это появилось в документации по магистрали и обсуждается в потоке "eval re-allowed"

inline scripts не вернется, хотя:

Нет механизма для ослабления ограничения на выполнение встроенного JavaScript. В частности, установка политики script, которая включает 'unsafe-inline', не будет иметь никакого эффекта.

Ответ 3

Использование хеша для встроенных скриптов разрешено в Уровне безопасности контента 2. Из примера в спецификации:

Content-Security-Policy: script -src 'sha512-YWIzOWNiNzJjNDRlYzc4MTgwMDhmZDlkOWI0NTAyMjgyY2MyMWJlMWUyNjc1ODJlYWJhNjU5MGU4NmZmNGU3OAo ='

Альтернативой является nonce, опять же из примеров:

Content-Security-Policy: script -src 'self' 'nonce- $RANDOM';

затем

<script nonce="$RANDOM">...</script>
<script nonce="$RANDOM" src='save-because-nonce'></script>

Они отображаются в Chrome 40+, но я не уверен, какая удача была бы у других браузеров на данный момент.

Ответ 4

Afaik, это ошибка.

"default-src 'self' https://ssl.google-analytics.com"

работает, а

"default-src 'self' http://ssl.google-analytics.com"

оленьей кожи.

Это действительно технология с кровоточащими ребрами, проверьте http://code.google.com/p/chromium/issues/detail?id=105796 для деталей.

Обновление: http://code.google.com/p/chromium/issues/detail?id=107538 относится к этой проблеме.