跳出“框框”思考
既然“似乎”没有办法以“好”的方式做到这一点,人们总是可以运用一点创造力来实现特定的结果。
回顾一下:
-
要求是有一种方法来识别从哪里发出请求
- 这可以通过
Worker 调用手动实现,也可以自动实现
- 任何安全问题似乎都在其他地方处理
- 在调用时更改
Worker URL 可能有助于自动处理
可行的解决方案
这是一个可用于“劫持”某些类调用或方法的包装器:
const hijack = function(driver,victim,jacker)
{
if(((typeof driver)=='string')&&!victim){return this.plan[driver]}; // recap
if(victim in this.plan){return}; // only jack once? .. less cruel
this.plan[victim]={victim:driver[victim],jacker:jacker}; // plan the heist
let con = {enumerable:false,configurable:false,writable:false,value:function()
{
let car=hijack((this.mask||this.name||this.constructor.name)); let m=this.mask;
let arg=car.jacker.apply(null,arguments); if(!Array.isArray(arg)){arg=[arg]};
if(!m){return new (Function.prototype.bind.apply(car.victim,[null].concat(arg)))()}
else{return car.victim.apply(this,arg)};
}};
try{con.value.prototype = Object.create(driver[victim].prototype)} // blend in
catch(oops){Object.defineProperty(driver,'mask',{value:victim});}; // recover
Object.defineProperty(driver,victim,con);
}.bind({plan:{}});
...钉子遇到锤子
工作原理
- 它接受 3 个参数:
-
driver ~ 包含目标函数/方法的对象
-
victim ~ 将被拦截的函数/方法的名称
-
jacker ~ 一个回调函数 - 用于中继/更改参数
- 将原始方法复制到可以使用或后续调用的位置
- 回调强制(取消)原始参数,并且可以在调用者和被调用者之间传递不变的参数(与原始参数完全相同),但现在您可以控制它如何发生(如果有的话)以及准确传递什么;要么有一些简单的条件,要么有一些复杂的计划(又名“邪恶计划”)
- 为简单起见,这段代码(上图)只允许每个
victim 进行1 次拦截,但这可以扩展为多次拦截;通过“chain-relay”(回调数组)或“event-dispatcher + event-listener combo(s)”。
如何使用
具体问题:
hijack(window,'Worker',function(arg){return `${arg}?worker=true`});
为了解决 cmets 中的安全问题,api-key 可能很有用;因此,如果将一些 string 传递给当前会话(或客户端)唯一的正在运行的实例(浏览器或服务器),它就足够了,例如:
hijack(window,'Worker',function(arg){return `${arg}?worker=${window.ApiKey}`});
.. 其中ApiKey 被全局定义为string,但它也可以是函数调用的结果——从cookie 中获取它,或者其他。
有用的工具
这也可用于增强安全性。如果您担心 devtools 发出的 XHR 请求甚至更糟:eval( ) - 那么你可以使用这个hijack 来全局拦截这些调用/调用。
例如:
hijack(URL,'createObjectURL',function(arg){console.log(arg); return `whatever`});
如果您打算将其用作安全工具,那么它需要一些 TLC 以及一些“调用堆栈回溯”、“突变观察器”......以及一些(暗)物质(:
免责声明
在此练习中没有人受伤 .. 受害者没事 .. 自行决定使用 p>