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



react-devtools react-native (8)

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

显然,由于最近发生的诈骗事件,开发者工具被人们利用来发布垃圾邮件,甚至被用于“黑客”账户。 Facebook阻止了开发者工具,我甚至无法使用控制台。

他们是怎么做到的?? 一个堆栈溢出帖子声称这是不可能的 ,但Facebook已经证明他们错了。

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

这怎么可能?

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


Answer #1

这不是弱代码无人照管的安全措施。 在实施该策略之前,始终要对弱代码进行永久性解决,并妥善保护您的网站

根据我的知识,迄今为止最好的工具是添加多个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秒间隔可能会对访问者可能使用的较旧计算机产生严重影响


Answer #2

我是Facebook的安全工程师,这是我的错。 我们正在对一些用户进行测试,看看它是否能够减缓用户被诱骗将(恶意)JavaScript代码粘贴到浏览器控制台中的一些攻击。

只是要清楚:试图阻止黑客客户端是一个普遍的坏主意 , 这是为了防范特定的社会工程攻击

如果你最终进入了测试组,并对此感到恼火,对不起。 我试图尽可能简单地使旧的退出页面(现在的帮助页面 )尽可能简单,同时仍然足够可怕地阻止至少一些受害者。

实际的代码非常类似于@ joeldixon66的链接 ; 没有很好的理由,我们的情况稍微复杂一些。

Chrome将所有控制台代码包装进来

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

...所以该网站重新定义了console._commandLineAPI抛出:

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

这还不够(尝试!) ,但这是主要的伎俩。

结语:Chrome团队决定从用户端JS击败控制台是个bug并解决了这个问题 ,使得这种技术失效。 之后,又添加了额外的保护措施,以保护用户免受自我xss的侵害


Answer #3

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以引发安全错误。


Answer #4

这实际上是可能的,因为Facebook能够做到这一点。 那么,不是实际的Web开发人员工具,而是在控制台中执行Javascript。

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

这真的不会做太多,因为有其他方法可以绕过这种类型的客户端安全。

当你说它是客户端的时候,它发生在服务器的控制之外,所以你可以做的事情不多。 如果你问为什么Facebook仍然这样做,这不是真正的安全问题,而是为了保护那些不知道JavaScript的普通用户从运行代码(他们不知道如何阅读)到控制台中。 对于那些承诺自动提供者服务或其他Facebook功能机器人的网站,在你做他们要求你做的事情时,这是很常见的,在大多数情况下,他们会给你一段javascript的控制台。

如果你的用户没有Facebook那么多,那么我认为没有必要去做Facebook的工作。

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

并且如果浏览器在地址栏中禁用javascript(当您将代码粘贴到Google Chrome中的地址栏时,它会删除短语'javascript:'),但仍然可以通过检查元素将javascript粘贴到其中一个链接中。

检查锚点:

将代码粘贴到href中:

底线是服务器端验证和安全性应该是第一,然后做客户端之后。


Answer #5

我使用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);

有了这个,控制台自动完成将自动失败,而在控制台中输入的语句将无法执行(将记录异常)。

参考文献:


Answer #6

除了重新定义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]您会期望得到以下输出:

在monkedypatching InjectedScript._evaluateAndWrap评估相同的表达式之后,给出以下输出:

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

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

另外,请看一下is - InjectedScriptHost -对象。 它提供了一些方法来玩,并对督察的内部进行了一些了解。

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

只需在返回console.log (res)console.log (res)替换else路径中的return语句即可。 那么你最终会得到以下结果。

编辑结束

这是谷歌修复的以前的版本。 因此不再是可能的方式。

其中之一是挂钩到Function.prototype.call

Chrome通过将thisArg作为thisArg call其eval函数来评估输入的表达式

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

鉴于此,您可以监听正在evaluatecall这个thisArg ,并获取对第一个参数( 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);  
        }
    };
}

你可能会抛出一个错误,评估被拒绝。

下面是一个example ,其中输入的表达式在传递给evaluate函数之前传递给CoffeeScript编译器。


Answer #7

我的简单方法,但它可以帮助进一步变化这个问题。 列出所有方法并将其改为无用。

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




google-chrome-devtools