Як Facebook відключає інтегровані Інструменти для розробників браузера?


1685

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

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

Як вони це зробили ?? Один повідомлення про переповнення стека стверджував, що це неможливо , але Facebook довів їх неправильно.

Просто перейдіть до Facebook і відкрийте інструменти для розробників, введіть один символ у консоль, і це попередження спливе. Що б ви не помістили, воно не буде виконано.

Як це можливо?

Вони навіть заблокували автоматичне завершення в консолі:

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


21
Просто для розваги: ​​console.log = function () {}
tnt-rox

Ви знайшли рішення , як вони блокували автомобіль повною функції в консолі
Акшай Хедж

1
@AkshayHegde Це був побічний ефект, викликаний блокуванням будь-якого виконання коду з devtools.
Дерек 朕 會 功夫

@Derek朕會功夫ви можете , будь ласка , код акції
Акшай Хедж

просто фію, це вже не заблоковано в хромі.
Іван Лорд

Відповіді:


2437

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

Щоб було зрозуміло: намагання заблокувати хакерів на стороні клієнта - це взагалі погана ідея ; це захист від конкретної атаки на соціальну інженерію .

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

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

Chrome обертає весь код консолі

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

... так що сайт переробляє, console._commandLineAPIщоб кинути:

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

Цього недостатньо (спробуйте!) , Але це головна хитрість.


Епілог: Команда Chrome вирішила, що перемогти консоль від JS на стороні користувача - помилка, і вирішив проблему , зробивши цю техніку недійсною. Після цього було додано додатковий захист для захисту користувачів від self-xss .


10
Chrome зробив оновлення, але цей хлопець зробив виправлення знову: kspace.in/blog/2014/06/21/…
Роджер Гаджрай

3
@Alf, на вашій сторінці відмови тепер відображається сторінка довідки без можливості вимкнути цей захист.
arm.localhost

168
Будь ласка, не порушуйте інструменти для розробників через дурість деяких користувачів. "Такі рішення" змушують мене горіти від люті мільйона сонців.
Джонатан Данлап

85
Я думаю, що Google повинен випустити "безпечну" версію Chrome, без DevTools, і змусити когось із автоматичних оновлень перейти на цю версію лише один раз. Будь-який розробник, який фактично помічає різницю і потребує DevTools, повинен завантажити "страшну" версію. Насправді позначте їх як "Страшно" та "Безпечно" безпосередньо на сторінці завантаження та відмовляйте Дарвінянам від заподіяння шкоди, прямо заявляючи, що "Ви, ймовірно, тут, тому що атака соціальних інженерів сказала вам завантажити версію Страшно; зробити це." Нехай Бог благословить вас чортів на те, що ви такі творчі!
MonkeyZeus

11
@ n00b Це попередження - це просто console.log.
gcampbell

91

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

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);

При цьому автоматичне завершення консолі виходить з ладу, тоді як заяви, введені в консолі, не вдасться виконати (виняток буде зареєстровано).

Список літератури:


48

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

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

console.log('test');

Для стилізації виводу: Кольори в консолі JavaScript

Редагувати Мислення @ joeldixon66 має правильну ідею: Вимкнути виконання JavaScript з консолі «::: KSpace :::


класно, але все-таки переотримайте те саме window.console.log = function(){//empty}і скористайтеся console.log
супер круто

32

Окрім переосмислення console._commandLineAPI, є й інші способи прориву InjectedScriptHost у браузерах WebKit, щоб запобігти чи змінити оцінку виразів, введених у консоль розробника.

Редагувати:

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's 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's 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's 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]ви очікуєте наступного результату:

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

Після маніпулювання за InjectedScript._evaluateAndWrapоцінкою того самого виразу, дає такий вихід:

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

Як ви бачите ліворуч стрілку, що вказує на вихід, все ще є, але на цей раз ми отримуємо об'єкт. Де результат виразу, масив[1,2,3,4] представлений у вигляді об'єкта з усіма описаними властивостями.

Я рекомендую спробувати оцінити цей і той вираз, включаючи ті, що генерують помилки. Це досить цікаво.

Додатково подивіться на об’єкт is - InjectedScriptHost- . Він пропонує деякі методи, з якими можна пограти та трохи ознайомитись із внутрішністю інспектора.

Звичайно, ви можете перехопити всю цю інформацію і все-таки повернути початковий результат користувачеві.

Просто замініть оператор return у шляху else на console.log (res)наступне a return res. Тоді ви б закінчилися з наступним.

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

Кінець редагування


Це попередня версія, яку було виправлено Google. Отже, більше не можливий шлях.

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

Chrome оцінює введений вираз, використовуючи callфункцію eval за допомогою InjectedScriptHostякthisArg

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

З огляду на це, ви можете слухати до thisArgз 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);  
        }
    };
}

Ви можете, наприклад, нанести помилку, що оцінка була відхилена.

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

Ось приклад, коли введений вираз передається компілятору CoffeeScript перед передачею його evaluateфункції.


25

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щоб кинути помилку безпеки.


24

Це фактично можливо, оскільки Facebook це зміг зробити. Ну, не власне інструменти веб-розробників, а виконання Javascript у консолі.

Дивіться це: Як Facebook відключає інтегровані Інструменти для розробників браузера?

Це дійсно багато не вдається, хоча є й інші способи обійти безпеку на рівні клієнта.

Коли ви кажете, що це клієнт, це відбувається поза контролем сервера, тому ви не можете з цим зробити багато. Якщо ви запитуєте, чому Facebook все ще робить це, це насправді не для безпеки, а для захисту звичайних користувачів, які не знають JavaScript, від запущеного коду (який вони не вміють читати) в консоль. Це звичайно для сайтів, які обіцяють службу автоматичного користування або інші боти функціональності Facebook після того, як ви зробите те, що вони просять вас зробити, де в більшості випадків вони надають вам фрагмент JavaScript для запуску в консолі.

Якщо у вас немає стільки користувачів, скільки Facebook, то я не думаю, що потрібно робити те, що робить Facebook.

Навіть якщо ви відключите Javascript у консолі, запуск JavaScript через адресний рядок все ще можливий.

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

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

і якщо веб-переглядач відключає JavaScript в адресному рядку, (Коли ви вставляєте код до адресного рядка в Google Chrome, він видаляє фразу 'javascript:') вставлення javascript в одне із посилань через елемент перевірки все ще можливо.

Огляньте якір:

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

Код вставки в href:

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

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

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

Підсумок - це перевірка на стороні сервера і спочатку має бути захист, а потім - клієнт.


11

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(){};
}

9

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

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

5

Внутрішньо 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);
});


Це досить акуратно, але воно також розбиває сторінку.
Дерек 朕 會 功夫

@Derek 朕 會 功夫 Єдиний спосіб (я знайшов) придушити подальше введення користувачем
samdd

Цікаво, чи можна викинути помилку замість нескінченного циклу. Редагувати: Тестовано, не працює.
Дерек 朕 會 功夫

@Derek 朕 會 功夫 знаходиться в блоці спробувати. Ви, ймовірно, могли б замінити функції над блоком, але це лише запобіжить автоматичному завершенню (не оцінці)
samdd

2

просте рішення!

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

1
Як це відключити console.log()?
Червоний

1
console.log()більше не має значення, коли консоль постійно прибирається :)
Mohmmad Ebrahimi Aval

це погана ідея. хакер може простежити їх термінал і переглянути всі журнали.
GFxJamal

4
і якщо ви позначите прапор "Зберегти журнали", console.clear () нічого не робить: P
Zibri

0

Я б пішов шляхом:

Object.defineProperty(window, 'console', {
  get: function() {

  },
  set: function() {

  }
});

-2

Це не міра безпеки, щоб слабкий код залишався без нагляду. Завжди отримуйте постійне рішення для слабкого коду та належним чином захищайте свої веб-сайти перед реалізацією цієї стратегії

На мій досвід, найкращим інструментом було б додавання декількох файлів 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 секунду на великих сторінках можуть мати різкі наслідки для старих комп'ютерів, якими користувачі можуть користуватися.


це ... це не гарний підхід.
RozzA
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.