Для последних версий Chrome (46+) текущий ответ больше не соответствует действительности. unsafe-inline
все еще не имеет никакого эффекта (в манифесте и в meta
тегах заголовка), но согласно документации , вы можете использовать описанный метод здесь , чтобы ослабить ограничение. 1007 *
Использование хэша для <script>
элементов
Директива script-src
позволяет разработчикам вносить в белый список определенный встроенный скрипт, указав его хэш в качестве разрешенного источника скрипта.
Использование просто. Сервер вычисляет хэш содержимого конкретного блока скрипта и включает в себя кодировку 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>
Результат
Дальнейшее расследование
Я также протестировал помещение соответствующей директивы в тег meta
вместо манифеста. Несмотря на то, что CSP, указанный в сообщении консоли, действительно содержит содержимое тега, он не будет выполнять встроенный сценарий (в Chrome 53).
new 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))
- В JS используется криптографическая библиотека Stanford 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);
}
Убедитесь, что при хэшировании встроенных сценариев включено содержимое тега сценария целом (включая все начальные / конечные пробелы). Если вы хотите включить это в свои сборки, вы можете использовать что-то вроде 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 для генерации хешей.