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

Der*_*會功夫 1652 javascript facebook google-chrome-devtools

显然,由于最近的骗局,开发人员工具被人们利用来发布垃圾邮件,甚至用来"破解"帐户.Facebook已经阻止了开发人员工具,我甚至无法使用控制台.

在此输入图像描述

他们是怎么做到的??One Stack Overflow帖子声称这是不可能的,但Facebook证明他们错了.

只需转到Facebook并打开开发人员工具,在控制台中键入一个字符,然后弹出此警告.无论你投入什么,它都不会被执行.

这怎么可能?

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

在此输入图像描述

Alf*_*Alf 2397

我是Facebook的安全工程师,这是我的错.我们正在为一些用户测试这一点,看看它是否可以减慢用户被欺骗将(恶意)JavaScript代码粘贴到浏览器控制台中的一些攻击.

需要明确的是:一般来说,试图阻止黑客客户端是一个坏主意 ; 这是为了防止特定的社会工程攻击.

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

实际代码与@ joeldixon66的链接非常相似; 没有充分理由,我们的情况要复杂得多.

Chrome包含所有控制台代码

with ((console && console._commandLineAPI) || {}) {
  <code goes here>
}
Run Code Online (Sandbox Code Playgroud)

...所以网站重新定义console._commandLineAPI:

Object.defineProperty(console, '_commandLineAPI',
   { get : function() { throw 'Nooo!' } })
Run Code Online (Sandbox Code Playgroud)

这还不够(试试吧!),但那是主要的伎俩.


结语:Chrome团队决定从用户端JS中取消控制台是一个错误并修复了问题,导致此技术无效.之后,添加了额外的保护以保护用户免受自我xss的侵害.

  • 由于某些用户的愚蠢行为,请不要破坏开发人员工具.像这样的"解决方案"让我燃烧着一百万个太阳的愤怒. (158认同)
  • 我认为谷歌需要发布Chrome的"安全"版本,没有DevTools,并强制任何人进行自动更新,只需切换到此版本一次.任何真正注意到差异并需要DevTools的开发人员都应下载"可怕"版本.事实上,直接在下载页面上将它们标记为"可怕"和"安全",并通过明确声明"你可能在这里因为社会工程攻击告诉你下载可怕版本而阻止达尔文主义者造成伤害;请不要做这个." 上帝保佑你FB开发者如此有创意! (75认同)
  • Chrome确实做了更新,但是这个人再次修复了这个问题:http://kspace.in/blog/2014/06/21/revisiting-disable-javascript-execution-from-console/ (10认同)
  • @ n00b该警告消息只是一个`console.log`. (10认同)
  • @Alf,您的选择退出页面现在显示帮助页面,没有任何关闭此保护的可能性. (3认同)
  • @LONGMAN Chrome小组[已修复](https://code.google.com/p/chromium/issues/detail?id=345205). (3认同)

Sal*_*n A 83

我使用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);
Run Code Online (Sandbox Code Playgroud)

这样,控制台自动完成将无声地失败,而在控制台中键入的语句将无法执行(将记录异常).

参考文献:


Wil*_*ill 43

我无法在任何页面上触发它.一个更强大的版本可以做到这一点:

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

console.log('test');
Run Code Online (Sandbox Code Playgroud)

设置输出样式:JavaScript控制台中的颜色

编辑思考@ joeldixon66有正确的想法:从控制台«::: KSpace :::禁用JavaScript执行


Mor*_*ler 30

除了重新定义之外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);
Run Code Online (Sandbox Code Playgroud)

它有点冗长,但我想我对它提出了一些意见

通常情况下,例如,如果用户评估[1,2,3,4]您希望得到以下输出:

在此输入图像描述

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

在此输入图像描述

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

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

此外,看一看的is - InjectedScriptHost-对象.它提供了一些方法,可以深入了解检查员的内部情况.

当然,您可以拦截所有信息并仍然将原始结果返回给用户.

只需用console.log (res)以下a 替换else路径中的return语句即可return res.然后你最终得到以下内容.

在此输入图像描述

编辑结束


这是由Google修复的先前版本.因此不再是一种可能的方式.

其中一个是挂钩 Function.prototype.call

Chrome call通过其eval函数InjectedScriptHostas 来评估输入的表达式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);  
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

你可以抛出一个错误,评价被拒绝了.

在此输入图像描述

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


Fiz*_*han 23

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$$) {
    }
})();
Run Code Online (Sandbox Code Playgroud)

他们只是覆盖console._commandLineAPI以抛出安全错误.


Jom*_*ejo 23

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

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

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

当你说它是客户端时,它发生在服务器的控制之外,因此你无能为力.如果你问为什么Facebook仍然这样做,这不是为了安全,而是为了保护那些不知道javascript的普通用户运行代码(他们不知道如何阅读)进入控制台.这对于承诺自动播放器服务或其他Facebook功能机器人的网站来说很常见,在您执行他们要求您执行的操作之后,在大多数情况下,他们会为您提供在控制台中运行的javascript片段.

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

即使你在控制台中禁用Javascript,仍然可以通过地址栏运行javascript.

在此输入图像描述

在此输入图像描述

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

检查锚:

在此输入图像描述

在href中粘贴代码:

在此输入图像描述

在此输入图像描述

在此输入图像描述

底线是服务器端验证,安全应该是第一个,然后是客户端.

  • "查看此"链接指向此页面. (4认同)

Dus*_*tic 8

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

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


Alp*_*a2k 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(){};
}
Run Code Online (Sandbox Code Playgroud)


sam*_*mdd 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);
});
Run Code Online (Sandbox Code Playgroud)