В настоящее время я работаю над проектом, где безопасность очень важна. По умолчанию все глобальные переменные/свойства, такие как Promise
или даже crypto
, могут быть перезаписаны.
Есть ли способ защитить их от перезаписи?
Пример:
window.crypto.getRandomValues = () => { return [1] }
window.crypto.getRandomValues(new Uint32Array(1))[0] // 1
Моей первой мыслью было использовать Object.freeze()
для блокировки объекта, но можно просто перезаписать метод Object.freeze
, чтобы он ничего не делал.
Мы уже очень избирательно относимся к используемым зависимостям, но я все же хотел бы убедиться, что эти переменные нельзя перезаписать. Или, по крайней мере, определить, были ли они перезаписаны.
возможно только правило eslint eslint.org/docs/rules/no-global-assign
Если пользователь хочет сделать это сам, я могу с этим смириться. Но я хочу, чтобы другие библиотеки не мешали моей. Итак, если блокировка глобальных переменных невозможна, есть ли способ «изолировать» различные зависимости? Я прочитал предложение о realms
. Я думаю, что это было бы то, что я ищу, но это еще не готово.
Отказ от ответственности: все это только грубый набросок, тщательно не проверенный. Я уверен, что есть еще проблемы, которые нужно решить.
замораживание объект-окно не вариант, это просто вызовет проблемы, но, может быть, такие объекты, как window.crypto
?
Но вы можете переопределить свойства, чтобы они больше не изменялись, даже для оконного объекта.
function freezeProp(target, propertyName) {
const { value, get = () => value, set = () => void 0, ...desc } = Object.getOwnPropertyDescriptor(target, propertyName);
Object.defineProperty(target, propertyName, { ...desc, get, set, configurable: false });
}
freezeProp(window, "crypto");
Но эти методы работают только в том случае, если вы можете убедиться, что вы запускаете скрипт первым.
Обнаружение того, были ли изменены некоторые методы, также возможно, если у вас есть ссылка на них; и мы снова стали первым запущенным скриптом.
Но если вы не уверены, что глобальная область видимости испорчена, почему бы не получить новый объект-окно?
window.crypto.getRandomValues = () => {
return [1]
};
const secure = (() => {
let iframe = document.createElement("iframe");
document.body.appendChild(iframe);
const contentWindow = iframe.contentWindow;
document.body.removeChild(iframe);
return contentWindow;
})();
var a = window.crypto.getRandomValues(new Uint8Array(1));
console.info(a);
var b = secure.crypto.getRandomValues(new Uint8Array(1));
console.info(b);
Вы пришли к тому же выводу, что и я. Вы должны убедиться, что первый замораживает / блокирует объекты, прежде чем кто-то другой сможет что-либо перезаписать. Похоже, ваше решение работает для криптографии, но, например, «Прокси» и «Обещание» все еще могут быть перезаписаны. Моя первоначальная мысль заключалась в том, чтобы создать const safeProxy = Proxy
и заблокировать его свойства, чтобы вы всегда могли полагаться на наличие safeProxy в его исходной форме. Кстати, ваш последний подход с iframe не работает, потому что можно просто перезаписать функцию document.createElement
:).
Это собственный браузер пользователя — в конце концов, они могут запускать любой код, какой хотят, и они также могут исправлять что угодно.