Facebook如何禁用浏览器的集成开发人员工具?


1685

显然,由于最近的骗局,开发人员工具被人们用来发布垃圾邮件,甚至被用来“破解”帐户。Facebook阻止了开发人员工具,我什至不能使用该控制台。

在此处输入图片说明

他们是怎么做到的??一篇Stack Overflow帖子声称这是不可能的,但是Facebook已经证明它们是错误的。

只需转到Facebook并打开开发人员工具,在控制台中键入一个字符,就会弹出此警告。不管您输入什么内容,都不会执行它。

这怎么可能?

他们甚至阻止了控制台中的自动完成:

在此处输入图片说明


21
只是为了好玩:console.log = function(){}
tnt-rox

您是否找到解决方案,以解决他们如何在控制台中阻止自动完成功能的问题
Akshay Hegde,

1
@AkshayHegde这是由于阻止从devtools执行的任何代码所引起的副作用。
德里克·朕会功夫,

@Derek朕会功夫就可以取悦共享代码
阿克沙伊赫格德

只是为了方便,它不再受镀铬的限制。
John Lord

Answers:


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/...
罗杰Gajraj

3
@Alf,您的退出页面现在显示帮助页面,没有任何可能关闭此保护。
arm.localhost 2015年

168
请不要因为某些用户的愚蠢而破坏开发人员工具。这样的“解决方案”使我燃烧了一百万个阳光。
乔纳森·邓拉普

85
我认为Google需要发布Chrome的“安全”版本,而不是DevTools,并强制任何需要自动更新的人切换到该版本一次。任何真正注意到差异并需要DevTools的开发人员都应下载“吓人”版本。实际上,直接在下载页面上将它们分别标记为“ Scary”和“ Safe”,并通过明确声明“您可能在这里是因为社交工程攻击告诉您下载吓人的版本,因此可能阻止达尔文人造成伤害”;请不要做这个。” 愿上帝保佑FB开发者如此有创造力!
MonkeyZeus

11
@ n00b该警告消息只是一个console.log
gcampbell '16

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有一个正确的主意:从控制台«::: KSpace :::禁用JavaScript执行


酷一个,但仍然覆盖相同的内容window.console.log = function(){//empty}并使用console.log
超级酷

32

除了重新定义之外console._commandLineAPI,还有其他一些方法可以在WebKit浏览器中闯入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]您进行评估,您将期望获得以下输出:

在此处输入图片说明

在monkeypatching计算InjectedScript._evaluateAndWrap出非常相同的表达式之后,给出以下输出:

在此处输入图片说明

如您所见,指示输出的小左箭头仍然存在,但是这次我们得到一个对象。在表达式的结果中,数组[1,2,3,4]表示为一个对象,并描述了其所有属性。

我建议尝试对此表达式进行评估,包括那些会产生错误的表达式。这很有趣。

此外,看一看的is - InjectedScriptHost-对象。它提供了一些可以使用的方法,并可以对检查器的内部结构有一些了解。

当然,您可以截取所有这些信息,并且仍将原始结果返回给用户。

只需将else路径中的return语句替换为console.log (res)跟随一个即可return res。然后,您将得到以下结果。

在此处输入图片说明

编辑结束


这是Google修复的先前版本。因此,不再有可能。

其中之一是迷上 Function.prototype.call

铬通过计算输入的表达call以1ng其eval函数InjectedScriptHost作为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);  
        }
    };
}

例如,您可能会抛出一个错误,即评估被拒绝。

在此处输入图片说明

这是一个示例,其中输入的表达式在传递给evaluate函数之前先传递给CoffeeScript编译器。


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能够做到。嗯,不是实际的Web开发人员工具,而是控制台中Javascript的执行。

请参见:Facebook如何禁用浏览器的集成开发人员工具?

但这确实不会做太多,因为还有其他方法可以绕过这种客户端安全性。

当您说它是客户端时,它发生在服务器的控制之外,因此您无能为力。如果您问为什么Facebook仍会这样做,这并不是出于安全性考虑,而是要保护不了解javascript的普通用户从控制台中运行代码(他们不知道如何阅读)。对于承诺在您执行他们要求做的事情后提供自动相似服务或其他Facebook功能机器人的网站,这种情况很常见,在大多数情况下,它们会为您提供一小段可在控制台中运行的JavaScript。

如果您没有Facebook那样多的用户,那么我认为没有必要做Facebook正在做的事情。

即使您在控制台中禁用了Javascript,仍然可以通过地址栏运行JavaScript。

在此处输入图片说明

在此处输入图片说明

并且如果浏览器禁用了地址栏上的javascript,(将代码粘贴到Google Chrome浏览器中的地址栏时,它将删除短语“ javascript:”),则仍然可以通过inspect元素将javascript粘贴到链接之一中。

检查锚点:

在此处输入图片说明

将代码粘贴到href中:

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

最重要的是应该首先进行服务器端验证和安全性,然后再进行客户端验证。


11

自从Facebook可能禁用控制台以来,Chrome发生了很大变化。

截至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

在devdevs内部,将一个IIFE getCompletions注入到页面中,当在Devtools控制台中按下某个键时会调用该IIFE。

查看该函数来源,它使用了一些可以覆盖的全局函数。

通过使用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


0

我会遵循以下方式:

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

  },
  set: function() {

  }
});

-2

这不是使弱代码无人看管的安全措施。在实施此策略之前,请始终获得弱代码的永久解决方案并正确保护您的网站

据我所知,到目前为止最好的工具是添加多个javascript文件,这些文件可以通过刷新或替换内容将页面的完整性简单地恢复为正常。禁用此开发人员工具不是最好的主意,因为绕行一直是个问题,因为代码是浏览器的一部分,而不是服务器渲染的一部分,因此可能会被破解。

如果您要js file one检查<element>重要元素的更改js file twojs 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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.