Использование SRI для решения проблемы захвата CDN

внешний интерфейс Безопасность

В последнее время проект часто сталкивался с захватом CDN, и я узнал, что с этим можно эффективно бороться с помощью Subresource Integrity.

Введение в НИИ

SRIПолное название Subresource Integrity — Subresource Integrity относится к функции безопасности, которую браузеры используют для проверки целостности ресурсов (обычно получаемых из CDN), чтобы определить, не были ли они подделаны.

Улучшите функцию SRI, добавив свойство Integrity в тег LINK или тег Script, например:

<script type="text/javascript" src="//s.url.cn/xxxx/aaa.js" 
    integrity="sha256-xxx sha384-yyy"
    crossorigin="anonymous"></script>

Значение целостности разделено на две части: первая часть определяет алгоритм генерации хеш-значения (sha256, sha384 и sha512), а вторая часть представляет собой фактическое хэш-значение, закодированное с помощью base64, разделенное дефисом (-). Значение целостности может содержать несколько хэшей, разделенных пробелами, и если файл соответствует любому из этих хэшей, ресурс можно проверить и загрузить. В приведенном выше примере я использовал две схемы хеширования sha256 и sha384.

Примечание:crossorigin="anonymous"Функция состоит в том, чтобы ввести междоменные сценарии. В HTML5 есть способ получить информацию об ошибках междоменных сценариев. Во-первых, сервер междоменных сценариев должен разрешить текущему доменному имени получать информацию об ошибках через доступ -Controll-Allow-Origin информация заголовка, а затем Тег скрипта, который является текущим доменным именем, должен также объявить, что он поддерживает междоменный атрибут, то есть атрибут crossorigin. Такие теги, как link и img, поддерживают междоменные сценарии. Если вышеуказанные два условия не могут быть выполнены, вы можете использоватьtry catchстроить планы.

Зачем использовать СИ

В веб-разработке использование ресурсов CDN может эффективно сократить время сетевых запросов, но также существует проблема с использованием ресурсов CDN, поскольку ресурсы CDN существуют на сторонних серверах и не полностью контролируются с точки зрения безопасности.

Перехват CDN — очень сложная проблема для обнаружения.Во-первых, угонщик будет использовать определенный алгоритм или случайный метод, чтобы захватить его (хитро), поэтому его очень трудно воспроизвести, и многие пользователи обновят страницу после появления и больше не появится. Ранее коллега в компании сталкивался с этой проблемой с загрузчиком игры.После того как пользователь скачал игру, после распаковки в нее нельзя было играть.Позже путем сравнения файлов по одному была найдена причина.Выяснилось быть вызвано перехватом CDN. Как это решить? Я слышал, что плата за защиту была оплачена на xx, а метод использования хэша файла был использован позже.Он должен быть таким же, как SRI в принципе.

К счастью, большая часть текущего угона CDN заключается в том, чтобы просто выполнить какое-то увлечение, например, вставить некоторые рекламные исправления через iframe, если у угонщика есть скрытые мотивы, такие как внедрение xss, это все еще очень опасно.

Включение SRI может эффективно обеспечить целостность ресурсов ссылок на страницы и избежать выполнения вредоносного кода.

Как браузеры обрабатывают SRI

  • Когда браузер встречает атрибут целостности в скрипте или теге ссылки, он сравнивает хэш загруженного файла с ожидаемым хешем перед выполнением скрипта или применением таблицы стилей.
  • Когда хэш сценария или таблицы стилей не соответствует ожидаемому, браузер ДОЛЖЕН отказаться от выполнения сценария или применения таблицы стилей и ДОЛЖЕН вернуть сетевую ошибку, указывающую, что получение сценария или таблицы стилей не удалось.

Использование СИ

С помощью модулей webpack html-webpack-plugin и webpack-subresource-integrity можно генерировать теги сценариев, содержащие атрибут целостности.

import SriPlugin from 'webpack-subresource-integrity'
 
const compiler = webpack({
    output: {
        crossOriginLoading: 'anonymous',
    },
    plugins: [
        new SriPlugin({
            hashFuncNames: ['sha256', 'sha384'],
            enabled: process.env.NODE_ENV === 'production',
        })
    ]
})

Итак, что мне делать, если проверка SRI скрипта или ресурса ссылки не удалась?

Лучший способ — использовать событие скрипта onerror для перезагрузки ресурсов между статическими файловыми серверами при обнаружении onerror:

<script type="text/javascript" src="//11.url.cn/aaa.js"
        integrity="sha256-xxx sha384-yyy"
        crossorigin="anonymous"
        onerror="loadScriptError.call(this, event)"
        onsuccess="loadScriptSuccess"></script>

Вставьте следующий код перед этим:

(function () {
	function loadScriptError (event) {
		// 上报
		...
		// 重新加载 js
		return new Promise(function (resolve, reject) {
			var script = document.createElement('script')
			script.src = this.src.replace(/\/\/11.src.cn/, 'https://x.y.z') // 替换 cdn 地址为静态文件服务器地址
			script.onload = resolve
			script.onerror = reject
			script.crossOrigin = 'anonymous'
			document.getElementsByTagName('head')[0].appendChild(script)
		})
	}
	function loadScriptSuccess () {
		// 上报
		...
	}
	window.loadScriptError = loadScriptError
	window.loadScriptSuccess = loadScriptSuccess
})()

Что более болезненно, так это то, что событие в onerror не может определить, что вызвало ошибку.Может быть, что ресурс не существует, или может быть, что проверка SRI не удалась.Конечно, наиболее частым случаем является тайм-аут запроса, но в настоящее время, если нет статистического требования, нет большой проблемы с неизбирательным обращением.

Внедрить событие onerror

Конечно, так как теги script в проекте упакованы webpack, нам нужно использоватьscript-ext-html-webpack-pluginДобавьте события onerror и onsuccess:

const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')

module.exports = {
  //...
  plugins: [
    new HtmlWebpackPlugin(),
    new SriPlugin({
      hashFuncNames: ['sha256', 'sha384']
    }),
	new ScriptExtHtmlWebpackPlugin({
	  custom: {
	    test: /\/*_[A-Za-z0-9]{8}.js/,
	    attribute: 'onerror',
	    value: 'loadScriptError.call(this, event)'
	  }
	}),
	new ScriptExtHtmlWebpackPlugin({
	  custom: {
	    test: /\/*_[A-Za-z0-9]{8}.js/,
	    attribute: 'onsuccess',
	    value: 'loadScriptSuccess.call(this, event)'
	  }
	})
  ]
}

Затем внедрите методы loadScriptError и loadScriptSuccess в html, вы можете использовать встроенный метод.

Как судить о захвате CDN?

Как упоминалось ранее, сбой загрузки скрипта может быть вызван различными причинами, так как же определить, произошел ли перехват CDN?

Метод заключается в том, чтобы запросить данные еще раз, дважды сравнить содержимое файла (конечно, сравнивать все не обязательно), если содержимое несовместимо, можно сделать вывод.

function loadScript (url) {
	return fetch(url).then(res => {
		if (res.ok) {
			return res
		}
		return Promise.reject(new Error())
	  }).then(res => {
	  	return res.text()
	}).catch(e => {
		return ''
	})
}

Сравните, является ли скрипт, загруженный дважды, одинаковым

function checkScriptDiff (src, srcNew) {
	return Promise.all([loadScript(src), loadScript(srcNew)]).then(data => {
		var res1 = data[0].slice(0, 1000)
		var res2 = data[1].slice(0, 1000)
		if (!!res1 && !!res2 && res1 !== res2) {
			// CDN劫持事件发生
		}
	}).catch(e => {
		// ...
	})
}

Почему здесь сравниваются только первые 1000 символов? Поскольку угонщики CDN обычно внедряют некоторый код в верхнюю часть js-файла для достижения своей цели, внедрение промежуточного кода требует синтаксического анализа AST, который является дорогостоящим, поэтому бессмысленно сравнивать все строки. Если у вас все еще есть проблемы, вы можете добавить сравнение последних n символов.

наконец

Я также видел великого бога на Zhihu, который нашел другой способ решить проблему захвата CDN, подобный jsonp. Лично я считаю, что этот метод отлично справляется с перехватом CDN. Основная причина в том, что операторы осуществляют перехват через сопоставление имен файлов. Метод автора заключается в обнаружении перехвата через onerror и удалении суффикса js файлов ресурсов для борьбы с перехватом CDN. .

Что может сделать внешний интерфейс, чтобы справиться с перехватом трафика?

Эта статья имеет четкую идею и настоятельно рекомендуется для изучения.


Технологический еженедельник IVWEBШок в сети, обратите внимание на публичный номер: сообщество IVWEB, регулярно каждую неделю публикуйте качественные статьи.

  • Сборник статей еженедельника:weekly