显然,由于最近的骗局,开发者工具被人们用来发布垃圾邮件,甚至被用来“黑客”账户。Facebook已经屏蔽了开发者工具,我甚至无法使用控制台。
他们是怎么做到的??一篇Stack Overflow的帖子声称这是不可能的,但Facebook已经证明他们错了。
只需转到Facebook并打开开发工具,在控制台中键入一个字符,就会弹出此警告。无论你投入什么,它都不会被执行。
这怎么可能?
他们甚至在控制台中阻止了自动完成:
显然,由于最近的骗局,开发者工具被人们用来发布垃圾邮件,甚至被用来“黑客”账户。Facebook已经屏蔽了开发者工具,我甚至无法使用控制台。
他们是怎么做到的??一篇Stack Overflow的帖子声称这是不可能的,但Facebook已经证明他们错了。
只需转到Facebook并打开开发工具,在控制台中键入一个字符,就会弹出此警告。无论你投入什么,它都不会被执行。
这怎么可能?
他们甚至在控制台中阻止了自动完成:
当前回答
我使用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);
这样,当在控制台中键入的语句将无法执行时,控制台自动完成将以静默方式失败(将记录异常)。
参考文献:
对象定义属性对象.getOwnPropertyDescriptorChrome的console.log功能(用于格式化输出的提示)
其他回答
我的方法很简单,但它有助于这个主题的进一步变化。列出所有方法并将其更改为无用。
Object.getOwnPropertyNames(console).filter(function(property) {
return typeof console[property] == 'function';
}).forEach(function (verb) {
console[verb] =function(){return 'Sorry, for security reasons...';};
});
然而,更好的方法是禁止以任何有意义的方式打开开发人员工具
(function() {
'use strict';
Object.getOwnPropertyNames(console).filter(function(property) {
return typeof console[property] == 'function';
}).forEach(function (verb) {
console[verb] =function(){return 'Sorry, for security reasons...';};
});
window.addEventListener('devtools-opened', ()=>{
// do some extra code if needed or ...
// maybe even delete the page, I still like to add redirect just in case
window.location.href+="#";
window.document.head.innerHTML="";
window.document.body.innerHTML="devtools, page is now cleared";
});
window.addEventListener('devtools-closed', ()=>{
// do some extra code if needed
});
let verifyConsole = () => {
var before = new Date().getTime();
debugger;
var after = new Date().getTime();
if (after - before > 100) { // user had to resume the script manually via opened dev tools
window.dispatchEvent(new Event('devtools-opened'));
}else{
window.dispatchEvent(new Event('devtools-closed'));
}
setTimeout(verifyConsole, 100);
}
verifyConsole();
})();
在Firefox中,它没有做到这一点,因为Firefox是一个开发人员浏览器,我认为由于命令WEBGL_debug_render_info在Firefox中被弃用,将被删除。请使用RENDERER和错误Referrer Policy:对于跨站点请求,将很快忽略限制较少的策略,包括“降级时没有Referrer”、“跨源时源”和“不安全url”:https://static.xx.fbcdn.net/rsrc.php/v3/yS/r/XDDAHSZfaR6.js?_nc_x=Ij3Wp8lg5Kz.
这实际上是可能的,因为Facebook能够做到这一点。嗯,不是实际的web开发工具,而是在控制台中执行Javascript。
看看这个:Facebook如何禁用浏览器的集成开发工具?
但这真的没什么用,因为还有其他方法可以绕过这种类型的客户端安全性。
当你说它是客户端时,它发生在服务器的控制之外,所以你对此无能为力。如果你问Facebook为什么仍然这样做,这实际上不是为了安全,而是为了保护不懂javascript的普通用户,防止他们在控制台中运行代码(他们不知道如何读取)。这对于那个些承诺自动点赞服务或其他Facebook功能机器人的网站来说是很常见的,他们会在你们完成他们要求你们做的事情后,给你们一小段javascript,让你们在控制台中运行。
如果你没有Facebook那么多的用户,那么我认为没有必要做Facebook正在做的事情。
即使在控制台中禁用Javascript,也可以通过地址栏运行Javascript。
如果浏览器在地址栏禁用javascript,(当你在Google Chrome中将代码粘贴到地址栏时,它会删除短语“javascript:”)仍然可以通过inspect元素将javascript粘贴到其中一个链接中。
检查锚固件:
在href中粘贴代码:
底线是服务器端验证和安全性应该首先进行,然后再进行客户端验证。
除了重新定义控制台_命令行API,还有一些其他方法可以在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]求值,则会得到以下输出:
猴痘注射后_evaluateAndWrap对相同的表达式求值,给出以下输出:
如您所见,指示输出的小左箭头仍然存在,但这次我们得到了一个对象。在表达式的结果中,数组[1,2,3,4]表示为一个对象,并描述了其所有财产。
我建议尝试评估这个和那个表达式,包括那些产生错误的表达式。这很有趣。
此外,查看is-InjectedScriptHost-对象。它提供了一些方法来使用和深入了解检查器的内部。
当然,您可以截取所有这些信息,并仍然将原始结果返回给用户。
只需将else路径中的return语句替换为后跟return res的console.log(res)即可。
编辑结束
这是Google修复的先前版本。因此不再是一种可能的方式。
其中一个是挂接到Function.prototype.call
Chrome通过使用InjectedScriptHost作为thisArg调用其eval函数来计算输入的表达式
var result=evalFunction.call(对象,表达式);
考虑到这一点,您可以监听正在求值的调用的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);
}
};
}
例如,您可以抛出一个错误,即评估被拒绝。
下面是一个示例,输入的表达式在传递给求值函数之前被传递给CoffeeScript编译器。
我使用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);
这样,当在控制台中键入的语句将无法执行时,控制台自动完成将以静默方式失败(将记录异常)。
参考文献:
对象定义属性对象.getOwnPropertyDescriptorChrome的console.log功能(用于格式化输出的提示)