Что может сделать функция hijacking? Секрет передовой черной технологии

JavaScript

Что такое перехват функций? По сути, это добавить к вызываемой функции функцию-оболочку, а в функции-оболочке вызвать исходную функцию, что немного похоже на роль прокси-сервера.Он перехватывает некоторые глобальные объекты и методы, и может реализовывать некоторые очень удобные глобальные функции.

Жизнь слишком коротка, console.log украшение страданий

Некоторое время назад я увидел анимацию значка эмодзи в адресной строке. Было очень интересно и занимательно. Я попытался применить эмодзи к примеру с захватом функций, который я исследовал. Реальный эффект неплох. Получайте удовольствие, и поделитесь им со всеми, чтобы добавить немного света в унылую жизнь разработчиков.

console.log сам поддерживает стиль таблицы стилей.Добавьте %c к первому параметру для форматирования вывода, а второй параметр можно передать в таблицу стилей, что позволяет добиться очень красивых эффектов, таких как градиент цвета и отображение картинок. Можем ли мы заставить console.log изменять цвет по умолчанию? Мы пытаемся перехватить console.log, чтобы добавить к нему функцию по умолчанию, чтобы он каждый раз случайным образом менял цвет и значок для вывода. Чтобы защитить зрение, увеличьте размер шрифта на 1. Эффект будет следующим:

var _consoleLog=window.console.log;
window.console.log=function (){
    if(arguments.length==1 && typeof arguments[0]!="object"){
        var iconList=["🌏","🌛","🌟","🔥","🐦","👿","🎃","🎊","🎋","🎁","🍀","🌷","🌱","🍁","🌸","🍃","🌿","🍒","🍎","🍊","🍓","🍍","🍇"]
        var colorList=["background-color:#8BC34A;color:white",
                        "background-color:#42b983;color:white",
                        "background-color:#33A5FF;color:white",
                        "background-color:orange;color:white",
                        "background-color:#2EAFB0;color:white",
                        "background-color:#6EC1C2;color:white",
                        "background-color:#FFDD4D;color:black",
                        "background-color:#7F2B82;color:white",
                        "background-color:#4b4b4b;color:white",
                        "background-color:#E41A6A;color:white"]
        var idx1=Math.floor(Math.random()*iconList.length);
        var idx2=Math.floor(Math.random()*colorList.length);
        var msg=arguments[0];
        msg="%c "+iconList[idx1]+" "+msg;
        
        _consoleLog(msg,"font-size:20pt;"+colorList[idx2])
    }else{
        _consoleLog.apply(this,arguments)
    }
}

console.log("hello,world")

Внесите его в общедоступный код, и вы сможете каждый день видеть красочный вывод консоли. Примечание. Операционные системы Win 7 и более ранние версии не поддерживают цветное отображение выражений эмодзи.

Метод защиты от бликов: вывод json автоматически форматируется

JSON.stringify будет выводить JSON в одну строку, что очень некрасиво. Есть ли способ его украсить? Давайте посмотрим на документ mdn: JSON.stringify имеет 3 параметра, третий параметр может указывать пустую строку для отступа, который используется для украшения вывода (красивая печать); если параметр является числом, он показывает, сколько пробелов имеется; верхний предел 10. Если значение меньше 1, значит пробела нет, если параметр является строкой (первые десять букв строки), то строка будет считаться пробелом, тогда для чего используется второй параметр, он оказывается функцией обратного вызова для фильтрации каждого значения атрибута.Как правило, лучше не передавать значение null.

JSON.stringify({result:{a:1,b:2}},null,4)

Вывод уже отформатирован json, идеально:

{
    "result": {
        "a": 1,
        "b": 2
    }
}

Но передавать каждый раз по 3 параметра слишком утомительно.Кроме того, есть много студентов, которые не знают этого использования.Мы пытаемся инкапсулировать его с перехватом функций, чтобы он форматировался по умолчанию:

var _stringify=JSON.stringify
JSON.stringify=function (){
    if(arguments.length==1){
    	return _stringify(arguments[0],null,4)
    }else{
    	return _stringify.apply(this,arguments)
    }
}

Попробуйте JSON.stringify еще раз, вы можете отформатировать вывод, не передавая 3 параметра. Следует отметить, что перехват функции не должен выполняться повторно, иначе возникнет рекурсивный бесконечный цикл. Итак, как вы решаете, что он был взломан? Вызовите метод toString функции. Если это нативная функция, она вернет [нативный код] следующим образом

"function stringify() { [native code] }"

Просто выполните обнаружение символов.

Будьте готовы к черному дню и выполняйте оповещения против дешевых рук.

Некоторым новичкам нравится использовать оповещения для отладки. Если такой код появится в сети, это будет катастрофа. Давайте напишем hijack, чтобы навсегда устранить эту проблему:

window.alert=function (){
console.log(arguments[0])
}

Предупреждение, которое нельзя воспроизвести снова, как дела...

Настоящая черная технология 1: mock.js перехватывает ajax-запросы

Близится финал.В процессе разработки, где фронт и бэкенд разделены, неизбежно использование mock data.Есть два распространенных решения.

  1. Преимущество мокинга на стороне клиента в том, что нет необходимости строить сервер, а запрос перехватывается на фронтенде.
  2. Макет на стороне сервера состоит в том, чтобы создать пустой интерфейс и вернуть мертвые данные. Он относительно близок к процессу http-взаимодействия реальной среды.

Я сам реализовал подобную функцию mockjs много лет назад, и только потом узнал, что есть такой опенсорсный проект, который зря можно считать колесом. Его принцип по-прежнему заключается в захвате функции, захвате объекта window.XMLHttpRequest, в основном захвате метода отправки и события onreadystatechange.Захват отправки прост, как и предыдущий захват console.log, просто вложение функции более высокого порядка в инкапсулировать это сделано. , но как проксировать событие, к счастью, XHR не использует addEventListener для прослушивания событий, а использует уровень Dom 0 для прямого добавления обратных вызовов с именем события on, в противном случае нам нужно перехватить addEventListener, который является большая беда, если не будешь осторожен, тыкнешь в большую корзину.

Захват свойств объекта, конечно, использует метод defineProperty для перезаписи обратного вызова onreadystatechange. Если макет соответствует URL-адресу, он вернет его с ложными данными. Если он не соответствует, он не повлияет на другие обычные интерфейсы ajax, вызывая оригинальный процесс xhr. Ниже приведен полный исполняемый код.Для удобства демонстрации я опустил несколько необычных атрибутов и обычные базы правил сопоставления URL-адресов и использовал фиксированные адреса.

var __XMLHttpRequest=XMLHttpRequest;
window.XMLHttpRequest=function (){
       var resultObj={
           xhr:new __XMLHttpRequest(),
           onreadystatechange:null,
           open:function (method,url,async){
               this.url=url;
               this.method=method;
           },
           send:function (data){
               //用异步改下时序,让send 在 onreadystatechange  之后再执行
               setTimeout(()=> {
                   if(this.url.indexOf("http://www.baidu.com/post")>=0){    //匹配url规则,这个是业务代码省略掉了,先用固定地址
                       this.readyState=4;
                       this.status=200;
                       this.responseText="{result:'hello,baidu'}"; //为了演示先写死报文了
                       this.onreadystatechange({mock:true});
                   }else{
                       this.xhr.open(this.method,this.url);
                       this.xhr.send(data);
                   }
               }, 0);
           }
       }
       Object.defineProperty(resultObj,"onreadystatechange", {
           get:function (){
               return this.xhr.onreadystatechange;
           },
           set:function (func){
               this.xhr.onreadystatechange= (arg)=>{
                   if(arg.mock){ //mock接口,直接触发回调 
                       func();
                   }else{ //没匹配到,把原始xhr得到的数据复制回来
                       this.readyState=this.xhr.readyState;
                       this.status=this.xhr.status;
                       this.responseText=this.xhr.responseText;
                       func();
                   }
               };
           }
       })
       return resultObj;
}

Давайте напишем вариант использования и запустим его. Примечание: чтобы упростить код, место, где написан соответствующий URL-адрес, мертво, поэтому мы можем использовать только адрес http://www.baidu.com/post

var xhr=new XMLHttpRequest()
xhr.open("post","http://www.baidu.com/post");
xhr.send();
xhr.onreadystatechange=function (){
    console.log(xhr.responseText)
}

работает отлично, вывод {результат: 'привет, байду'} , что было невообразимо в прошлом. Ajax-запросы к несуществующему адресу также могут возвращать сообщение. . .

Настоящая черная технология 2: ненавязчивый мониторинг аномального уровня интерфейса, метод элегантного отбрасывания вины на задний план

Много лет назад у пользователей часто возникали какие-то проблемы, и воспроизвести разработку было сложно.Закулисные студенты больше нервничали, так что не бойтесь.Они часто не ведут логи,или говорят,что не могут найти журналы, а во внешнем интерфейсе нет журналов. В конце концов, фронтенд в основном отвечает. Позже наша команда фронтенда реализовала слой в слое xhr для отслеживания исключений и тайм-аутов фонового интерфейса, и элегантно свалил вину на фон, сэкономив кучу времени (на самом деле, многие из них связаны с серверными или сетевыми причинами, и фон действительно не может их обнаружить. ). Спустя годы, после того, как я понял макет, я понял, что прямой угон xhr - лучшее решение, которое можно использовать во всех проектах.В прошлом году я видел, как это сделала компания: www.fundebug.com, я очень доволен, много идей а у меня не совпадает. На самом деле коммерциализировать такое решение пока сложно, между технологией и коммерциализацией огромная пропасть.

Поговорим о его основном принципе

  • Прежде всего, глобальный захват исключений скрипта включает глобальное событие window.onerror.На стороне node.js есть событие uncaughtException, которое может захватывать информацию о типе исключения и стеке ошибок.Технология действительно меняется с каждым разом. Проходящий день.В эпоху браузера IE, onerror Событие вообще не имеет параметров.Если вы хотите получить стек исключений, вы можете только вернуться к функции стека, а затем toString через arguments.callee.caller.

  • Затем есть захват исключений уровня интерфейса.С помощью приведенного выше кода mock.js легко реализовать неинтрузивное обнаружение исключений интерфейса.Если макет не соответствует, он отправит запрос Ajax в обычном режиме и напрямую обнаружит код состояния и код состояния в readystatechange. Если код состояния окажется ненормальным, сообщите об этом. Конечно, если ваша фоновая ошибка по-прежнему возвращает код состояния 200, вы можете только сформулировать спецификацию сообщения и согласовать успешное возвращаемое значение. Если успешное ключевое слово не может быть обнаружено, все обрабатывают его как сбой и сообщают об этом в журнал.

  • Обнаружение тайм-аута интерфейса может добавить таймер setTimeout при отправке, если onreadystatechange не сработало к указанному времени, будет сообщено в журнале тайм-аута.

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

this.xhr.onreadystatechange= (arg)=>{
    if(arg.mock){ //mock接口,直接触发回调 
        func();
    }else{ //没匹配到,把原始xhr得到的数据复制回来
        if(this.readyState==4 && this.status!=200){
            reportError() //上报日志
        }
      //.......省略
    }
};

Суммировать

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

Наконец, я ежедневно рекомендую свои проекты с открытым исходным кодом:

webcontext, самый лаконичный фреймворк для веб-разработки node.js, адрес github:GitHub.com/ветер фантазии/…