In che modo Facebook disabilita gli Strumenti di sviluppo integrati del browser?


1685

Quindi apparentemente a causa delle recenti truffe, gli strumenti di sviluppo vengono sfruttati dalle persone per pubblicare spam e persino utilizzati per "hackerare" gli account. Facebook ha bloccato gli strumenti di sviluppo e non riesco nemmeno a utilizzare la console.

Inserisci qui la descrizione dell'immagine

Come hanno fatto a farlo ?? Un post di Stack Overflow ha affermato che non è possibile , ma Facebook li ha dimostrati sbagliati.

Basta andare su Facebook e aprire gli strumenti per sviluppatori, digitare un carattere nella console e viene visualizzato questo avviso. Non importa quello che hai inserito, non verrà eseguito.

Com'è possibile?

Hanno persino bloccato il completamento automatico nella console:

Inserisci qui la descrizione dell'immagine


21
Solo per divertimento: console.log = function () {}
tnt-rox

Hai trovato una soluzione per come hanno bloccato la funzione di completamento automatico nella console
Akshay Hegde,

1
@AkshayHegde È stato un effetto collaterale causato dal blocco di qualsiasi esecuzione di codice dagli sviluppatori.
Derek 28 會 功夫

@Derek 朕 會 功夫 puoi per favore condividere il codice
Akshay Hegde

a proposito, non è più bloccato in Chrome.
John Lord,

Risposte:


2438

Sono un ingegnere della sicurezza su Facebook e questa è colpa mia. Lo stiamo testando per alcuni utenti per vedere se può rallentare alcuni attacchi in cui gli utenti sono indotti a incollare codice JavaScript (dannoso) nella console del browser.

Giusto per essere chiari: cercare di bloccare gli hacker sul lato client è una cattiva idea in generale; questo serve a proteggere da uno specifico attacco di ingegneria sociale .

Se sei finito nel gruppo di test e ne sei infastidito, scusa. Ho cercato di rendere la vecchia pagina di opt-out (ora pagina di aiuto ) il più semplice possibile pur essendo abbastanza spaventosa da fermare almeno alcune delle vittime.

Il codice attuale è abbastanza simile al link di @ joeldixon66 ; la nostra è un po 'più complicata senza una buona ragione.

Chrome racchiude tutto il codice della console

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

... quindi il sito si ridefinisce console._commandLineAPIper lanciare:

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

Questo non è abbastanza (provalo!) , Ma questo è il trucco principale.


Epilogo: il team di Chrome ha deciso che sconfiggere la console da JS lato utente era un bug e risolto il problema , rendendo questa tecnica non valida. Successivamente, è stata aggiunta una protezione aggiuntiva per proteggere gli utenti da self-xss .


10
Chrome ha effettuato un aggiornamento ma questo ragazzo ha apportato nuovamente una correzione: kspace.in/blog/2014/06/21/…
Roger Gajraj,

3
@Alf, la tua pagina di esclusione ora mostra la pagina di aiuto senza alcuna possibilità di disattivare questa protezione.
arm.localhost il

168
Si prega di non rompere gli strumenti di sviluppo a causa della stupidità di alcuni utenti. "Soluzioni" come questa mi fanno bruciare con rabbia di un milione di soli.
Jonathan Dunlap,

85
Penso che Google debba rilasciare una versione "sicura" di Chrome, senza DevTools, e forzare chiunque su aggiornamenti automatici a passare a questa versione solo una volta. Qualsiasi sviluppatore che nota effettivamente la differenza e ha bisogno di DevTools dovrebbe scaricare la versione "spaventosa". In effetti, etichettali come "Scary" e "Safe" direttamente sulla pagina di download e scoraggia i darwiniani dal danneggiarsi dichiarando esplicitamente che "Probabilmente sei qui perché un attacco di ingegneria sociale ti ha detto di scaricare la versione Scary; per favore non Fai questo." Dio ti benedica sviluppatori FB per essere così creativo!
MonkeyZeus

11
@ n00b Quel messaggio di avviso è solo un console.log.
gcampbell,

91

Ho trovato lo script di buster della console di Facebook utilizzando gli strumenti di sviluppo di Chrome. Ecco lo script con lievi modifiche per la leggibilità. Ho rimosso i bit che non riuscivo a capire:

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

Con ciò, il completamento automatico della console fallisce silenziosamente mentre le istruzioni digitate console non verranno eseguite (l'eccezione verrà registrata).

Riferimenti:


48

Non sono riuscito a farlo innescare su nessuna pagina. Una versione più solida di questo lo farebbe:

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

console.log('test');

Per dare uno stile all'output: Colori nella console JavaScript

Modifica Thinking @ joeldixon66 ha l'idea giusta: disabilitare l'esecuzione di JavaScript dalla console «::: KSpace :::


cool, ma comunque sostituisci lo stesso window.console.log = function(){//empty}e usa console.log
super cool

32

Oltre a ridefinire console._commandLineAPI, ci sono altri modi per entrare in InjectedScriptHost nei browser WebKit, per prevenire o alterare la valutazione delle espressioni inserite nella console dello sviluppatore.

Modificare:

Chrome ha risolto questo problema in una versione precedente. - che deve essere stato prima di febbraio 2015, come ho creato l'essenza in quel momento

Quindi ecco un'altra possibilità. Questa volta ci colleghiamo, un livello sopra, direttamente InjectedScriptpiuttosto che InjectedScriptHostin contrasto con la versione precedente.

Il che è carino, dato che puoi direttamente applicare la patch alle scimmie InjectedScript._evaluateAndWrapinvece di dover fare affidamento InjectedScriptHost.evaluateperché ciò ti dà un controllo più preciso su ciò che dovrebbe accadere.

Un'altra cosa piuttosto interessante è che possiamo intercettare il risultato interno quando viene valutata un'espressione e restituirla all'utente invece del normale comportamento.

Ecco il codice, che fa esattamente questo, restituisce il risultato interno quando un utente valuta qualcosa nella console.

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

È un po 'prolisso, ma ho pensato di aggiungere alcuni commenti

Quindi normalmente, se un utente, ad esempio, valuta, [1,2,3,4]ti aspetteresti il ​​seguente output:

inserisci qui la descrizione dell'immagine

Dopo il monkeypatch che InjectedScript._evaluateAndWrapvaluta la stessa espressione, fornisce il seguente output:

inserisci qui la descrizione dell'immagine

Come vedi la piccola freccia sinistra, che indica l'output, è ancora lì, ma questa volta otteniamo un oggetto. Dove il risultato dell'espressione, l'array [1,2,3,4]è rappresentato come un oggetto con tutte le sue proprietà descritte.

Consiglio di provare a valutare questa e quell'espressione, comprese quelle che generano errori. È abbastanza interessante

Inoltre, dai un'occhiata all'oggetto is - InjectedScriptHost- . Fornisce alcuni metodi con cui giocare e ottenere un po 'di conoscenza degli interni dell'ispettore.

Naturalmente, potresti intercettare tutte quelle informazioni e comunque restituire all'utente il risultato originale.

Basta sostituire la dichiarazione di ritorno nel percorso else con un console.log (res)seguente a return res. Quindi finiresti con il seguente.

inserisci qui la descrizione dell'immagine

Fine modifica


Questa è la versione precedente che è stata riparata da Google. Quindi non è più possibile.

Uno di questi è agganciarsi Function.prototype.call

Chrome valuta l'espressione immessa inserendo callla sua funzione di valutazione con InjectedScriptHostasthisArg

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

Detto questo, è possibile ascoltare per la thisArgdi callessere evaluatee di ottenere un riferimento al primo argomento ( 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);  
        }
    };
}

Ad esempio, è possibile che venga visualizzato un errore relativo al rifiuto della valutazione.

inserisci qui la descrizione dell'immagine

Ecco un esempio in cui l'espressione immessa viene passata a un compilatore CoffeeScript prima di passarla alla evaluatefunzione.


25

Netflix implementa anche questa funzione

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

Sostituiscono semplicemente console._commandLineAPIper generare un errore di sicurezza.


24

Questo è effettivamente possibile poiché Facebook è stato in grado di farlo. Bene, non gli attuali strumenti di sviluppo web ma l'esecuzione di Javascript in console.

Vedi questo: In che modo Facebook disabilita gli Strumenti di sviluppo integrati del browser?

Questo non farà molto, tuttavia, poiché esistono altri modi per aggirare questo tipo di sicurezza lato client.

Quando dici che è lato client, succede al di fuori del controllo del server, quindi non c'è molto che puoi fare al riguardo. Se stai chiedendo perché Facebook lo fa ancora, questo non è proprio per sicurezza ma per proteggere gli utenti normali che non conoscono javascript dall'esecuzione di codice (che non sanno leggere) nella console. Questo è comune per i siti che promettono il servizio di auto-liker o altri robot di funzionalità di Facebook dopo aver fatto quello che ti chiedono di fare, dove nella maggior parte dei casi ti danno un taglio di javascript da eseguire in console.

Se non hai tanti utenti come Facebook, non penso che ci sia bisogno di fare ciò che sta facendo Facebook.

Anche se disabiliti Javascript nella console, è comunque possibile eseguire javascript tramite la barra degli indirizzi.

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

e se il browser disabilita javascript nella barra degli indirizzi, (quando si incolla il codice nella barra degli indirizzi in Google Chrome, elimina la frase "javascript:") incollare javascript in uno dei collegamenti tramite l'elemento inspect è ancora possibile.

Ispezionare l'ancora:

inserisci qui la descrizione dell'immagine

Incolla il codice in href:

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

La linea di fondo è la convalida sul lato server e la sicurezza dovrebbe essere prima di tutto, quindi dopo il lato client.


11

Chrome è cambiato molto dai tempi in cui Facebook poteva disabilitare la console ...

A marzo 2017 non funziona più.

La cosa migliore che puoi fare è disabilitare alcune delle funzioni della console, ad esempio:

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

Il mio modo semplice, ma può aiutare per ulteriori variazioni su questo argomento. Elencare tutti i metodi e modificarli in inutili.

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

5

Devtools internamente inietta un IIFE chiamato getCompletionsnella pagina, chiamato quando viene premuto un tasto all'interno della console Devtools.

Osservando l' origine di tale funzione , utilizza alcune funzioni globali che possono essere sovrascritte.

Usando il Errorcostruttore è possibile ottenere lo stack di chiamate, che includerà getCompletionsquando chiamato da Devtools.


Esempio:

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


È abbastanza pulito, ma blocca anche la pagina.
Derek 朕 會 功夫

@Derek 朕 會 功夫 Unico modo (ho trovato) per sopprimere ulteriori input dell'utente
samdd

Mi chiedo se puoi lanciare un errore invece di usare un ciclo infinito. Modifica: testato, non funziona.
Derek 朕 會 功夫

@Derek 朕 會 功夫 è in un blocco catch tentativo. Probabilmente potresti sovrascrivere le funzioni sopra il blocco, ma impedirebbe solo il completamento automatico (non la valutazione)
samdd

2

una soluzione semplice!

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

1
Come disabilita questo console.log()?
Red

1
console.log()non importa più quando la console viene costantemente ripulita :)
Mohmmad Ebrahimi Aval

Questa è una cattiva idea. l'hacker può rintracciare dal proprio terminale e vedere tutti i registri.
GFxJamal

4
e se contrassegni Preserve Logs, console.clear () non fa nulla: P
Zibri

0

Vorrei seguire la strada di:

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

  },
  set: function() {

  }
});

-2

Questa non è una misura di sicurezza per il codice debole da lasciare incustodito. Ottieni sempre una soluzione permanente al codice debole e proteggi correttamente i tuoi siti Web prima di implementare questa strategia

Lo strumento migliore di gran lunga secondo la mia conoscenza sarebbe quello di aggiungere più file javascript che semplicemente riportano l'integrità della pagina alla normalità aggiornando o sostituendo il contenuto. Disabilitare questo strumento di sviluppo non sarebbe la migliore idea poiché il bypass è sempre in discussione poiché il codice fa parte del browser e non è un rendering del server, quindi potrebbe essere crackato.

Se dovessi js file oneverificare la presenza di <element>modifiche su elementi importanti js file twoe js file threeverificare che questo file esista per periodo, avrai il completo ripristino dell'integrità sulla pagina entro il periodo.

Facciamo un esempio dei 4 file e mostriamo cosa intendo.

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

Ora questo è solo per mostrare che funziona anche su tutti i file e tag

   #heading {
   background-color:red;
   }

Se metti insieme tutti questi file e costruisci l'esempio vedrai la funzione di questa misura. Questo eviterà alcune iniezioni indesiderate se lo dovessi implementare correttamente su tutti gli elementi importanti nel tuo file indice, specialmente quando lavori con PHP.

Il motivo per cui ho scelto ricaricare invece di tornare al valore normale per attributo è il fatto che alcuni utenti malintenzionati potrebbero avere un'altra parte del sito Web già configurata e pronta e riduce la quantità di codice. La ricarica rimuoverà tutto il duro lavoro dell'attaccante e probabilmente giocherà da qualche parte più facilmente.

Un'altra nota: questo potrebbe diventare un sacco di codice, quindi tienilo pulito e assicurati di aggiungere definizioni a cui appartengono per facilitare le modifiche in futuro. Impostare anche i secondi sull'importo preferito in quanto intervalli di 1 secondo su pagine di grandi dimensioni potrebbero avere effetti drastici sui computer più vecchi che i visitatori potrebbero utilizzare


questo ... questo non è un buon approccio.
RozzA
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.