Проверяем, есть ли у нативной JavaScript‑функции манкипатч

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Кратко: как можно понять, была ли переопределена нативная JavaScriptфункция? Никак — или не совсем надежно. Способы есть, но полностью доверять им нельзя.

Нативные функции в JavaScript

В JavaScript «нативная функция» — это функция, исходный код которой был скомпилирован в машинный код. Нативные функции можно найти в стандартных встроенных объектах JavaScript (таких, как eval(), parseInt() и т. д.) и веб-API браузеров (таких, как fetch(), localStorage.getItem() и т. д.).

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

Манкипатчинг

Манкипатчинг, в основном, используется для изменения поведения встроенных API и нативных функций браузера. Часто, это единственный способ добавить специфичную функциональность, полифиллы или «зацепиться» за API, который иначе изменить невозможно.

Например, инструменты мониторинга, такие как Bugsnag, переопределяют интерфейсы Fetch и XMLHttpRequest, чтобы получить представление о сетевых подключениях, запускаемых кодом JavaScript.

Манкипатчинг — это мощный, но опасный метод, потому что код, который вы переопределяете, не находится под вашим контролем: будущие обновления движка JavaScript могут нарушить предположения, сделанные в вашем патче, и вызвать серьезные ошибки.

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

По этим (и многим другим) причинам может понадобиться проверить, является ли данная функция нативной или она имеет манкипатч… Но получится ли?

Использование toString() для проверки того, что у функции есть манкипатч

Самый распространенный способ проверить, является ли функция «чистой» (то есть, без манкипатча) — это проверить вывод ее toString().

По умолчанию, нативная функция toString() возвращает что-то вроде строки "function fetch() { [native code] }":

Эта строка может немного отличаться в зависимости от того, какой движок JavaScript используется. Тем не менее в большинстве браузеров вы можете с уверенностью предположить, что эта строка будет включать подстроку "[native code]".

Если нативная функция будет иметь манкипатч, ее toString() перестанет возвращать строку "[native code]" в пользу возврата тела функции в виде строки.

Таким образом, простой способ проверить, является ли функция по-прежнему нативной — это проверить, содержит ли ее вывод toString() строку "[native code]".

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

function isNativeFunction(f) {
  return f.toString().includes("[native code]");
}

isNativeFunction(window.fetch); // → true

// Манкипатч fetch API
(function () {
  const { fetch: originalFetch } = window;
  window.fetch = function fetch(...args) {
    console.log("Вызов fetch перехвачен:", ...args);
    return originalFetch(...args);
  };
})();

window.fetch.toString(); // → "function fetch(...args) {\n console.log("Fetch...

isNativeFunction(window.fetch); // → false

Этот подход отлично работает в большинстве случаев. Однако, его легко обойти, заставив считать, что функция по-прежнему нативна, когда это не так. Будь то злой умысел (например, вредоносное изменение кода) или потому, что кто-то хочет скрыть факт переопределения. Есть несколько способов, которыми вы можете сделать функцию «нативной».

Например, вы можете добавить код (или даже комментарий!) в тело функции, содержащий строку "[native code]":

(function () {
  const { fetch: originalFetch } = window;
  window.fetch = function fetch(...args) {
    // function fetch() { [native code] }
    console.log("Вызов fetch перехвачен:", ...args);
    return originalFetch(...args);
  };
})();

window.fetch.toString(); // → "function fetch(...args) {\n // function fetch...

isNativeFunction(window.fetch); // → true

…Или вы можете переопределить метод toString(), чтобы он возвращал строку, содержащую "[native code]":

(function () {
  const { fetch: originalFetch } = window;
  window.fetch = function fetch(...args) {
    console.log("Вызов fetch перехвачен:", ...args);
    return originalFetch(...args);
  };
})();

window.fetch.toString = function toString() {
  return `function fetch() { [native code] }`;
};

window.fetch.toString(); // → "function fetch() { [native code] }"

isNativeFunction(window.fetch); // → true

…Или вы можете создать функцию с манкипатчем, используя bind, которая генерирует нативную функцию:

(function () {
  const { fetch: originalFetch } = window;
  window.fetch = function fetch(...args) {
    console.log("Вызов fetch перехвачен:", ...args);
    return originalFetch(...args);
  }.bind(window.fetch); // 						
Источник: https://habr.com/ru/post/682028/


Интересные статьи

Интересные статьи

Привет, HABR!Все те кто пользуются системой мониторинга Zabbix, с большой вероятностью, уже использовали UserParameter. Это, безусловно, очень полезный инструмент позволяющий значительно расширить баз...
Если вы работали в больших компаниях, то знаете, что это за ощущение: у вас вроде бы есть всё для реализации себя как профессионала, все условия для воплощения в жизнь любых идей и задач — однако что-...
Что лучше для web-приложений - монолит или микросервисы? Многие ответят на этот вопрос, что, мол, все инструменты хороши, если их использовать по назначению. В таком случ...
Давайте представим, что мы получили бэк-коннект в результате эксплуатации RCE-уязвимости в условном PHP-приложении. Но едва ли это соединение можно назвать полноценным. Сегодня разбер...
Каждый лишний элемент на сайте — это кнопка «Не купить», каждая непонятность или трудность, с которой сталкивается клиент — это крестик, закрывающий в браузере вкладку с вашим интернет-магазином.