Как Facebook отключает встроенные инструменты разработчика?

Таким образом, по-видимому, из-за недавних атак, инструменты разработчика используются людьми для публикации спама и даже используются для "взлома" учетных записей. Facebook заблокировал инструменты разработчика, и я даже не могу использовать консоль.

Enter image description here

Как они это сделали? Один пост утверждал, что это невозможно, но Facebook доказал их не так.

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

Как это возможно?

Они даже заблокировали автозаполнение в консоли:

Enter image description here

Ответ 1

Я инженер по безопасности в Facebook, и это моя вина. Мы тестируем это для некоторых пользователей, чтобы увидеть, может ли он замедлить некоторые атаки, когда пользователи обманываются при вставке (вредоносном) JavaScript-коде в консоль браузера.

Просто, чтобы быть ясным: попытка блокировать хакеров на стороне клиента - это плохая идея в целом; это защита от конкретной социальной инженерной атаки.

Если вы оказались в тестовой группе и раздражены этим, извините. Я попытался сделать старую страницу отказа (сейчас справочная страница) настолько простой, насколько это возможно, хотя все еще достаточно страшно, чтобы остановить хотя бы некоторые из жертвы.

Фактический код очень похож на @joeldixon66 link; наш немного сложнее без уважительной причины.

Chrome завершает весь консольный код в

with ((console && console._commandLineAPI) || {}) {
  <code goes here>
}

... поэтому сайт переопределяет console._commandLineAPI, чтобы бросить:

Object.defineProperty(console, '_commandLineAPI',
   { get : function() { throw 'Nooo!' } })

Это недостаточно (попробуйте!), но что основной трюк.


Эпилог: команда Chrome решила, что победить консоль на стороне пользователя JS было ошибкой, а исправил проблему, делая эту технику недействительной. Впоследствии дополнительная защита была добавлена ​​в защитить пользователей от self-xss.

Ответ 2

Я нашел консольный консоль Facebook script с помощью инструментов разработчика Chrome. Вот script с незначительными изменениями для удобочитаемости. Я удалил биты, которые я не мог понять:

Object.defineProperty(window, "console", {
    value: console,
    writable: false,
    configurable: false
});

var i = 0;
function showWarningAndThrow() {
    if (!i) {
        setTimeout(function () {
            console.log("%cWarning message", "font: 2em sans-serif; color: yellow; background-color: red;");
        }, 1);
        i = 1;
    }
    throw "Console is disabled";
}

var l, n = {
        set: function (o) {
            l = o;
        },
        get: function () {
            showWarningAndThrow();
            return l;
        }
    };
Object.defineProperty(console, "_commandLineAPI", n);
Object.defineProperty(console, "__commandLineAPI", n);

При этом консоль автоматически завершает работу, пока команды, введенные в консоли, не будут выполнены (исключение будет записано в журнал).

Литература:

Ответ 3

Я не мог заставить его запускать это на любой странице. Более надежная версия этого будет делать это:

window.console.log = function(){
    console.error('The developer console is temp...');
    window.console.log = function() {
        return false;
    }
}

console.log('test');

Чтобы стиль вывода: Цвета в консоли JavaScript

Edit Thinking @joeldixon66 имеет правильную идею: отключить выполнение JavaScript с консоли ": KSpace :

Ответ 4

Помимо переопределения console._commandLineAPI, есть и другие способы взломать InjectedScriptHost в браузерах WebKit, чтобы предотвратить или изменить оценку выражений, введенных в консоль разработчика.

Edit:

Chrome исправил это в прошлом выпуске. - это должно было быть до февраля 2015 года, когда я создал суть в то время

Итак, вот еще одна возможность. На этот раз мы подключаемся к уровню выше непосредственно в InjectedScript вместо InjectedScriptHost в отличие от предыдущей версии.

Какой вид приятный, так как вы можете непосредственно патч обезьяны InjectedScript._evaluateAndWrap вместо того, чтобы полагаться на InjectedScriptHost.evaluate, поскольку это дает вам более тонкий контроль над тем, что должно произойти.

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

Вот код, который делает именно это, возвращает внутренний результат, когда пользователь оценивает что-то в консоли.

var is;
Object.defineProperty(Object.prototype,"_lastResult",{
   get:function(){
       return this._lR;
   },
   set:function(v){
       if (typeof this._commandLineAPIImpl=="object") is=this;
       this._lR=v;
   }
});
setTimeout(function(){
   var ev=is._evaluateAndWrap;
   is._evaluateAndWrap=function(){
       var res=ev.apply(is,arguments);
       console.log();
       if (arguments[2]==="completion") {
           //This is the path you end up when a user types in the console and autocompletion get evaluated

           //Chrome expects a wrapped result to be returned from evaluateAndWrap.
           //You can use `ev` to generate an object yourself.
           //In case of the autocompletion chrome exptects an wrapped object with the properties that can be autocompleted. e.g.;
           //{iGetAutoCompleted: true}
           //You would then go and return that object wrapped, like
           //return ev.call (is, '', '({test:true})', 'completion', true, false, true);
           //Would make `test` pop up for every autocompletion.
           //Note that syntax as well as every Object.prototype property get added to that list later,
           //so you won't be able to exclude things like `while` from the autocompletion list,
           //unless you wou'd find a way to rewrite the getCompletions function.
           //
           return res; //Return the autocompletion result. If you want to break that, return nothing or an empty object
       } else {
           //This is the path where you end up when a user actually presses enter to evaluate an expression.
           //In order to return anything as normal evaluation output, you have to return a wrapped object.

           //In this case, we want to return the generated remote object. 
           //Since this is already a wrapped object it would be converted if we directly return it. Hence,
           //`return result` would actually replicate the very normal behaviour as the result is converted.
           //to output what actually in the remote object, we have to stringify it and `evaluateAndWrap` that object again.`
           //This is quite interesting;
           return ev.call (is, null, '(' + JSON.stringify (res) + ')', "console", true, false, true)
       }
   };
},0);

Это немного многословно, но я подумал, что добавил в него несколько комментариев.

Так обычно, если пользователь, например, оценивает [1,2,3,4], вы ожидаете следующий вывод:

введите описание изображения здесь

После того, как monkeypatching InjectedScript._evaluateAndWrap оценивает одно и то же выражение, выдает следующий результат:

введите описание изображения здесь

Как вы видите, маленькая левая стрелка, указывающая вывод, все еще существует, но на этот раз мы получаем объект. Где результат выражения, массив [1,2,3,4] представляется как объект со всеми его описанными свойствами.

Я рекомендую попробовать оценить это и это выражение, включая те, которые генерируют ошибки. Это довольно интересно.

Кроме того, взгляните на объект is - InjectedScriptHost -. Он предоставляет некоторые методы для игры и дает представление о внутренних функциях инспектора.

Конечно, вы можете перехватить всю эту информацию и вернуть исходный результат пользователю.

Просто замените оператор return в пути else на console.log (res), следуя за return res. Тогда вы получите следующее.

введите описание изображения здесь

Конец редактирования


Это предварительная версия, которая была исправлена ​​Google. Следовательно, это не возможный путь.

Один из них подключается к Function.prototype.call

Chrome оценивает введенное выражение call с его функцией eval с помощью InjectedScriptHost как thisArg

var result = evalFunction.call(object, expression);

Учитывая это, вы можете прослушать thisArg of call как evaluate и получить ссылку на первый аргумент (InjectedScriptHost)

if (window.URL) {
    var ish, _call = Function.prototype.call;
    Function.prototype.call = function () { //Could be wrapped in a setter for _commandLineAPI, to redefine only when the user started typing.
        if (arguments.length > 0 && this.name === "evaluate" && arguments [0].constructor.name === "InjectedScriptHost") { //If thisArg is the evaluate function and the arg0 is the ISH
            ish = arguments[0];
            ish.evaluate = function (e) { //Redefine the evaluation behaviour
                throw new Error ('Rejected evaluation of: \n\'' + e.split ('\n').slice(1,-1).join ("\n") + '\'');
            };
            Function.prototype.call = _call; //Reset the Function.prototype.call
            return _call.apply(this, arguments);  
        }
    };
}

Вы можете, например, выдать ошибку, чтобы оценка была отклонена.

enter image description here

<суб > Вот пример где введенное выражение передается компилятору CoffeeScript, прежде чем передать его функции evaluate.

суб >

Ответ 5

Netflix также реализует эту функцию

(function() {
    try {
        var $_console$$ = console;
        Object.defineProperty(window, "console", {
            get: function() {
                if ($_console$$._commandLineAPI)
                    throw "Sorry, for security reasons, the script console is deactivated on netflix.com";
                return $_console$$
            },
            set: function($val$$) {
                $_console$$ = $val$$
            }
        })
    } catch ($ignore$$) {
    }
})();

Они просто переопределяют console._commandLineAPI, чтобы вызвать ошибку безопасности.

Ответ 6

Это действительно возможно, так как Facebook смог это сделать. Ну, а не фактические инструменты для веб-разработчиков, но выполнение Javascript в консоли.

Смотрите: Как отключить Facebook встроенные средства разработки браузера?

Это действительно не так много, хотя, поскольку есть другие способы обойти эту защиту на стороне клиента.

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

Если у вас не так много пользователей, как Facebook, то я не думаю, что вам нужно делать то, что делает Facebook.

Даже если вы отключите Javascript в консоли, запуск javascript через адресную строку по-прежнему возможен.

введите описание изображения здесь

введите описание изображения здесь

и если браузер отключает javascript в адресной строке, (когда вы вставляете код в адресную строку в Google Chrome, он удаляет фразу "javascript:" ) вставка javascript в одну из ссылок через элемент проверки по-прежнему возможна.

Осмотреть якорь:

введите описание изображения здесь

Вставить код в href:

введите описание изображения здесь

введите описание изображения здесь

введите описание изображения здесь

Нижняя строка - это проверка на стороне сервера, и безопасность должна быть первой, а затем делать клиентскую сторону после.

Ответ 7

Chrome сильно изменился с тех пор, как facebook может отключить консоль...

По состоянию на март 2017 года это больше не работает.

Лучше всего вы можете отключить некоторые функции консоли, например:

if(!window.console) window.console = {};
var methods = ["log", "debug", "warn", "info", "dir", "dirxml", "trace", "profile"];
for(var i=0;i<methods.length;i++){
    console[methods[i]] = function(){};
}

Ответ 8

Мой простой способ, но он может помочь в дальнейших вариациях по этому вопросу. Перечислите все методы и измените их на бесполезные.

  Object.getOwnPropertyNames(console).filter(function(property) {
     return typeof console[property] == 'function';
  }).forEach(function (verb) {
     console[verb] =function(){return 'Sorry, for security reasons...';};
  });

Ответ 9

простое решение!

setInterval(()=>console.clear(),1500);

Ответ 10

Внутренне devtools вводит на страницу IIFE с именем getCompletions, вызываемый при нажатии клавиши внутри консоли Devtools.

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

Используя конструктор Error можно получить стек вызовов, который будет включать getCompletions при вызове Devtools.


Пример:

const disableDevtools = callback => {
  const original = Object.getPrototypeOf;

  Object.getPrototypeOf = (...args) => {
    if (Error().stack.includes("getCompletions")) callback();
    return original(...args);
  };
};

disableDevtools(() => {
  console.error("devtools has been disabled");

  while (1);
});

Ответ 11

Это не мера безопасности для того, чтобы слабый код оставался без присмотра. Всегда получайте постоянное решение для слабого кода и правильно защищайте свои веб-сайты, прежде чем применять эту стратегию

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

Если у вас есть js file one проверяющий изменения <element> на важных элементах и js file two и js file three проверки того, что этот файл существует за период, вы получите полное восстановление целостности на странице в течение периода.

Давайте возьмем пример из 4 файлов и покажем вам, что я имею в виду.

index.html

   <!DOCTYPE html>
   <html>
   <head id="mainhead">
   <script src="ks.js" id="ksjs"></script>
   <script src="mainfile.js" id="mainjs"></script>
   <link rel="stylesheet" href="style.css" id="style">
   <meta id="meta1" name="description" content="Proper mitigation against script kiddies via Javascript" >
   </head>
   <body>
   <h1 id="heading" name="dontdel" value="2">Delete this from console and it will refresh. If you change the name attribute in this it will also refresh. This is mitigating an attack on attribute change via console to exploit vulnerabilities. You can even try and change the value attribute from 2 to anything you like. If This script says it is 2 it should be 2 or it will refresh. </h1>
   <h3>Deleting this wont refresh the page due to it having no integrity check on it</h3>

   <p>You can also add this type of error checking on meta tags and add one script out of the head tag to check for changes in the head tag. You can add many js files to ensure an attacker cannot delete all in the second it takes to refresh. Be creative and make this your own as your website needs it. 
   </p>

   <p>This is not the end of it since we can still enter any tag to load anything from everywhere (Dependent on headers etc) but we want to prevent the important ones like an override in meta tags that load headers. The console is designed to edit html but that could add potential html that is dangerous. You should not be able to enter any meta tags into this document unless it is as specified by the ks.js file as permissable. <br>This is not only possible with meta tags but you can do this for important tags like input and script. This is not a replacement for headers!!! Add your headers aswell and protect them with this method.</p>
   </body>
   <script src="ps.js" id="psjs"></script>
   </html>

mainfile.js

   setInterval(function() {
   // check for existence of other scripts. This part will go in all other files to check for this file aswell. 
   var ksExists = document.getElementById("ksjs"); 
   if(ksExists) {
   }else{ location.reload();};

   var psExists = document.getElementById("psjs");
   if(psExists) {
   }else{ location.reload();};

   var styleExists = document.getElementById("style");
   if(styleExists) {
   }else{ location.reload();};


   }, 1 * 1000); // 1 * 1000 milsec

ps.js

   /*This script checks if mainjs exists as an element. If main js is not existent as an id in the html file reload!You can add this to all js files to ensure that your page integrity is perfect every second. If the page integrity is bad it reloads the page automatically and the process is restarted. This will blind an attacker as he has one second to disable every javascript file in your system which is impossible.

   */

   setInterval(function() {
   // check for existence of other scripts. This part will go in all other files to check for this file aswell. 
   var mainExists = document.getElementById("mainjs"); 
   if(mainExists) {
   }else{ location.reload();};

   //check that heading with id exists and name tag is dontdel.
   var headingExists = document.getElementById("heading"); 
   if(headingExists) {
   }else{ location.reload();};
   var integrityHeading = headingExists.getAttribute('name');
   if(integrityHeading == 'dontdel') {
   }else{ location.reload();};
   var integrity2Heading = headingExists.getAttribute('value');
   if(integrity2Heading == '2') {
   }else{ location.reload();};
   //check that all meta tags stay there
   var meta1Exists = document.getElementById("meta1"); 
   if(meta1Exists) {
   }else{ location.reload();};

   var headExists = document.getElementById("mainhead"); 
   if(headExists) {
   }else{ location.reload();};

   }, 1 * 1000); // 1 * 1000 milsec

ks.js

   /*This script checks if mainjs exists as an element. If main js is not existent as an id in the html file reload! You can add this to all js files to ensure that your page integrity is perfect every second. If the page integrity is bad it reloads the page automatically and the process is restarted. This will blind an attacker as he has one second to disable every javascript file in your system which is impossible.

   */

   setInterval(function() {
   // check for existence of other scripts. This part will go in all other files to check for this file aswell. 
   var mainExists = document.getElementById("mainjs"); 
   if(mainExists) {
   }else{ location.reload();};
   //Check meta tag 1 for content changes. meta1 will always be 0. This you do for each meta on the page to ensure content credibility. No one will change a meta and get away with it. Addition of a meta in spot 10, say a meta after the id="meta10" should also be covered as below.
   var x = document.getElementsByTagName("meta")[0];
   var p = x.getAttribute("name");
   var s = x.getAttribute("content");
   if (p != 'description') {
   location.reload();
   }
   if ( s != 'Proper mitigation against script kiddies via Javascript') {
   location.reload();
   }
   // This will prevent a meta tag after this meta tag @ id="meta1". This prevents new meta tags from being added to your pages. This can be used for scripts or any tag you feel is needed to do integrity check on like inputs and scripts. (Yet again. It is not a replacement for headers to be added. Add your headers aswell!)
   var lastMeta = document.getElementsByTagName("meta")[1];
   if (lastMeta) {
   location.reload();
   }
   }, 1 * 1000); // 1 * 1000 milsec

style.css

Теперь это просто показать, что он работает на всех файлах и тегах, а также

   #heading {
   background-color:red;
   }

Если вы поместите все эти файлы вместе и построите пример, вы увидите функцию этой меры. Это предотвратит некоторые непредвиденные инъекции, если вы правильно их реализуете во всех важных элементах вашего индексного файла, особенно при работе с PHP.

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

Еще одно замечание: это может стать большим количеством кода, поэтому держите его в чистоте и обязательно добавьте определения в том месте, где они принадлежат, чтобы сделать изменения в будущем. Также установите секунды в нужное количество, так как интервалы в 1 секунду на больших страницах могут иметь резкие последствия для старых компьютеров, которые могут использовать ваши посетители