Facebook은 브라우저의 통합 개발자 도구를 어떻게 비활성화합니까?


1685

최근의 사기로 인해 개발자 도구는 사람들이 스팸을 게시하고 계정을 "해킹"하는 데 사용됩니다. Facebook에서 개발자 도구를 차단했으며 콘솔을 사용할 수도 없습니다.

여기에 이미지 설명을 입력하십시오

그들은 어떻게 했습니까? 하나의 스택 오버플로 게시물은 불가능하다고 주장 했지만 Facebook은 그것들을 잘못 입증했습니다.

Facebook으로 이동하여 개발자 도구를 열고 콘솔에 한 문자를 입력하면이 경고가 나타납니다. 무엇을 넣더라도 실행되지 않습니다.

이것이 어떻게 가능한지?

그들은 콘솔에서 자동 완성을 차단했습니다.

여기에 이미지 설명을 입력하십시오


21
그냥 재미로 : console.log = function () {}
tnt-rox

콘솔에서 자동 완성 기능을 차단하는 방법에 대한 솔루션을 찾았습니까?
Akshay Hegde

1
@AkshayHegde devtools에서 코드 실행을 차단하여 발생하는 부작용입니다.
Derek 朕 會 功夫

@Derek 朕 會 功夫 당신은 코드를 공유 할 수 있습니까
Akshay Hegde

참고로 더 이상 크롬으로 차단되지 않습니다.
John Lord

답변:


2437

나는 페이스 북의 보안 엔지니어이고 이것이 내 잘못이다. 우리는 사용자가 (악의적 인) JavaScript 코드를 브라우저 콘솔에 붙여 넣도록 속이는 공격을 느리게 할 수 있는지 확인하기 위해 일부 사용자에 대해 이것을 테스트하고 있습니다.

해커를 클라이언트 측에서 차단하는 것은 일반적으로 나쁜 생각 입니다. 이것은 특정 사회 공학 공격 으로부터 보호하는 것 입니다.

테스트 그룹에 들어가서 이것에 대해 화가났다면 죄송합니다. 나는 적어도 일부 희생자들을 막을만큼 무서워하면서 오래된 옵트 아웃 페이지 (현재 도움말 페이지 )를 가능한 한 단순 하게 만들려고 노력했습니다 .

실제 코드는 @ joeldixon66의 링크 와 매우 유사합니다 . 우리는 아무 이유없이 조금 더 복잡합니다.

Chrome은 모든 콘솔 코드를

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

... 그래서 사이트는 다시 console._commandLineAPI던지기를 재정의 합니다.

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

이것으로는 충분하지 않습니다 (시도하십시오!) , 이것이 주된 속임수입니다.


에필로그 : 크롬 팀은 사용자 측 JS에서 콘솔을 격파하는 버그라고 결정 및 문제 해결 이 기술의 무효를 렌더링. 그 후 self-xss로부터 사용자보호하기 위해 추가 보호 기능이 추가되었습니다 .


10
크롬 업데이 트를 확인했지만이 사람은 다시 수정을했다 : kspace.in/blog/2014/06/21/...
로저 Gajraj을

3
@Alf, 옵트 아웃 페이지에 이제이 보호 기능을 해제 할 수있는 도움말 페이지가 표시됩니다.
arm.localhost

168
일부 사용자의 어리 석음으로 인해 개발자 도구를 중단하지 마십시오. 이와 같은 "솔루션"은 백만 태양의 분노로 화상을 입게 만듭니다.
Jonathan Dunlap

85
Google은 DevTools가없는 "안전한"Chrome 버전을 출시하고 자동 업데이트를 사용하는 사람은이 버전으로 한 번만 전환해야한다고 생각합니다. 실제로 차이점을 인식하고 DevTools가 필요한 개발자는 "scary"버전을 다운로드해야합니다. 실제로 다운로드 페이지에서 직접 "무서운"및 "안전"으로 레이블을 지정하고 Darwinians가 "사회 공학적 공격으로 인해 무서운 버전을 다운로드하라고 지시했기 때문에 여기에있을 가능성이 있습니다. 이 작업을 수행." FB 개발자들이 창의력을 발휘해 주셔서 신의 축복을 빕니다!
MonkeyZeus

11
@ n00b 경고 메시지는 단지 a console.log입니다.
gcampbell

91

Chrome 개발자 도구를 사용하여 Facebook의 콘솔 버스터 스크립트를 찾았습니다. 다음은 가독성을 약간 변경 한 스크립트입니다. 이해할 수없는 비트를 제거했습니다.

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를 사용하십시오
super cool

32

재정의 외에도 console._commandLineAPIWebKit 브라우저에서 InjectedScriptHost를 침입하여 개발자 콘솔에 입력 된 표현식의 평가를 방지하거나 변경하는 다른 방법이 있습니다.

편집하다:

Chrome은 지난 릴리스에서이 문제를 해결했습니다. -당시 요점을 만들었으므로 2015 년 2 월 이전에 있었어야합니다.

여기 또 다른 가능성이 있습니다. 이번에 는 이전 버전이 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매우 동일한 표현을 평가하는 monkeypatching 후 다음과 같은 결과가 나타납니다.

여기에 이미지 설명을 입력하십시오

보시다시피 출력을 나타내는 작은 왼쪽 화살표가 여전히 있지만 이번에는 객체를 얻습니다. 식의 결과에서 배열 [1,2,3,4]은 모든 속성이 설명 된 개체로 나타납니다.

오류를 생성하는 표현식을 포함하여이 표현식과 해당 표현식을 평가하는 것이 좋습니다. 꽤 흥미 롭습니다.

또한, 한 번 봐 걸릴 is - InjectedScriptHost- 객체. 인스펙터의 내부를 가지고 약간의 통찰력을 얻는 방법을 제공합니다.

물론 모든 정보를 가로 채어 원래 결과를 사용자에게 반환 할 수 있습니다.

else 경로의 return 문을 console.log (res)다음으로 대체하십시오 return res. 그런 다음 다음과 같이 끝납니다.

여기에 이미지 설명을 입력하십시오

편집 끝


이것은 Google에서 수정 한 이전 버전입니다. 따라서 더 이상 가능한 방법은 아닙니다.

그중 하나가 Function.prototype.call

Chrome은 다음 callInjectedScriptHost같이 eval 함수를 사용 하여 입력 한 표현식을 평가합니다.thisArg

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

이를 통해 thisArgcall존재를 듣고 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

페이스 북이 그것을 할 수 있었기 때문에 이것은 실제로 가능합니다. 실제 웹 개발자 도구가 아니라 콘솔에서 Javascript를 실행하는 것입니다.

다음을 참조하십시오 : Facebook은 브라우저의 통합 개발자 도구를 어떻게 비활성화합니까?

이 유형의 클라이언트 측 보안을 우회하는 다른 방법이 있기 때문에 실제로는 그렇게하지 않습니다.

클라이언트 측이라고 말하면 서버의 제어 외부에서 발생하므로 할 수있는 일이 많지 않습니다. Facebook에서 여전히이 작업을 수행하는 이유를 묻는 경우 이는 실제로 보안을위한 것이 아니라 Javascript를 모르는 일반 사용자가 코드를 읽는 방법 (알지 못하는)을 콘솔로 실행하지 못하도록 보호하는 것입니다. 이는 자동 요청 서비스 나 다른 Facebook 기능 봇을 요구하는 사이트가 대부분의 경우 콘솔에서 실행할 자바 스크립트를 제공하는 사이트에서 일반적입니다.

Facebook만큼 많은 사용자가 없다면 Facebook 이하는 일을 할 필요가 없다고 생각합니다.

콘솔에서 자바 스크립트를 비활성화하더라도 주소 표시 줄을 통해 자바 스크립트를 실행할 수 있습니다.

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

브라우저가 주소 표시 줄에서 자바 스크립트를 비활성화하면 (Chrome의 주소 표시 줄에 코드를 붙여 넣을 때 'javascript :'구문을 삭제합니다) inspect 요소를 통해 링크 중 하나에 javascript를 붙여 넣을 수 있습니다.

앵커를 점검하십시오.

여기에 이미지 설명을 입력하십시오

href에 코드 붙여 넣기 :

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

결론은 서버 측 유효성 검사이며 보안이 먼저 수행 된 다음 클라이언트 측에서 수행해야합니다.


11

페이스 북이 콘솔을 비활성화 할 수있는 시간 이후 크롬이 많이 바뀌 었습니다 ...

2017 년 3 월에 따라 더 이상 작동하지 않습니다.

가장 좋은 방법은 다음과 같은 일부 콘솔 기능을 비활성화하는 것입니다.

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 getCompletions는 페이지에 이름이 지정된 IIFE를 주입 하고 Devtools 콘솔에서 키를 누를 때 호출됩니다.

해당 함수소스를 살펴보면 덮어 쓸 수있는 몇 가지 전역 함수를 사용합니다.

Error생성자 를 사용하면 getCompletionsDevtools가 호출 할 때 포함되는 호출 스택을 얻을 수 있습니다.


예:

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 朕 會 功夫

@Derek 朕 會 功夫 추가 사용자 입력을 억제하는 유일한 방법 (발견)
samdd

무한 루프를 사용하는 대신 오류를 던질 수 있는지 궁금합니다. 편집 : 테스트되었으며 작동하지 않습니다.
Derek 朕 會 功夫

@Derek 朕 會 功夫 그것은 시도 캐치 블록에 있습니다. 블록 위의 기능을 무시할 수는 있지만 자동 완성 (평가는 아님) 만 막을 수 있습니다.
samdd

2

간단한 해결책!

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

1
이것은 어떻게 비활성화 console.log()합니까?
Red

1
console.log()콘솔이 지속적으로 정리 될 때 더 이상 문제가되지 않습니다 :)
Mohmmad Ebrahimi Aval

이것은 나쁜 생각입니다. 해커는 터미널에서 추적하여 모든 로그를 볼 수 있습니다.
GFxJamal

4
Preserve Logs 플래그를 지정하면 console.clear ()는 아무 것도 수행하지 않습니다 : P
Zibri

0

나는 길을 따라 갈 것입니다 :

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

  },
  set: function() {

  }
});

-2

이것은 약한 코드를 무인 상태로 방치하기위한 보안 조치가 아닙니다. 이 전략을 구현하기 전에 항상 약한 코드에 대한 영구적 인 솔루션을 얻고 웹 사이트를 올바르게 보호하십시오

내 지식에 따르면 가장 좋은 도구는 내용을 새로 고치거나 바꾸어 페이지의 무결성을 정상으로 다시 변경하는 여러 개의 자바 스크립트 파일을 추가하는 것입니다. 코드가 서버 렌더링이 아닌 브라우저의 일부이기 때문에 우회가 항상 문제가 되므로이 개발자 도구를 비활성화하는 것이 가장 좋은 아이디어는 아닙니다.

당신이해야 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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.