Javascript 窗口对象,窗口+,这段代码有什么作用



我正试图解决一个portswigger实验室(https://portswigger.net/web-security/cross-site-scripting/contexts/lab-javascript-url-some-characters-blocked)我不明白为什么当表达式窗口+''被省略时,这个代码没有弹出警报:

x=x=>{onerror=alert; throw 1337},toString=x,window+''

如果能对这个代码片段进行完整的解释,我们将不胜感激,谢谢。

首先,代码使用逗号运算符(另请参阅逗号在JavaScript表达式中的作用?(。逗号运算符的作用是允许您计算多个表达式。特别是在这种情况下,你有三个:

x=x=>{onerror=alert; throw 1337},toString=x,window+''
// ^______________________________^ ^________^ ^_______^
//                 1                     2         3

让我们逐一检查一下:

关于隐式全局变量的简要说明

这将与以下大部分部分相关,所以我想先澄清一下。任何时候分配给任何未用varletconst声明的名称时,它都会隐式分配给全局对象上的属性。在浏览器中,全局对象是window,因此任何隐含的全局都会转到那里:

console.log("before assignment");
console.log("'foo' in window:", 'foo' in window);
console.log("window.foo:", window.foo);
foo = 42;
console.log("after assignment");
console.log("'foo' in window:", 'foo' in window);
console.log("window.foo:", window.foo);

箭头函数

x=x=>{onerror=alert; throw 1337}

定义

这将创建一个新的箭头函数,并将其分配给x。由于没有变量声明,x将是一个隐式全局,因此附加到window。这并不是很有用——这样做可能是为了保存几个字符。该函数还接受一个名为x的参数,但对它不起任何作用。同样,没有什么用处-只保存一个字符,否则需要将其定义为()=>

车身部分1

更有趣的是这个函数的作用。

onerror=alert

首先,它将onerror分配给alert。这两者都将是全局错误处理程序和作为引用传递的全局alert()函数。因此,每当任何错误发生时,它都会显示一个警报:

window.onerror = alert;
JSON.parse("{"); // parsing error

请参阅函数调用和函数引用之间的区别是什么?以及在JavaScript中调用带括号和不带括号的函数的区别,以了解有关如何使用函数引用的更多信息。简而言之,如果您将一个函数分配给一个处理程序,那么调用该处理程序实际上会运行该函数。

车身部分2

然后,箭头函数抛出一个带有throw 1337的错误。在JavaScript中,您可以分配任何要抛出的值,所以它是否是错误并不重要。因此,抛出一个数字是有效的。抛出的值实际上并不相关,因为重要的是抛出一个错误。由于函数的第一部分,此throw语句将触发全局错误处理程序。这是一个演示(格式化(:

x = x => {
onerror = alert;
throw 1337
}
x();

到目前为止,一切都很好,但这不是代码中调用函数的方式。让我们进入下一部分。

覆盖toString

toString=x

此部分将覆盖window上的toString方法,并将其更改为x函数。因此,无论何时显式或隐式window转换为字符串,它都将执行x

x = x => {
onerror = alert;
throw 1337
}
toString = x;
window.toString();

window转换为字符串

在JavaScript中,当您尝试将任何值与字符串连接时,该值也将隐式转换为字符串。这通常通过调用toString()方法来完成:

const value1 = { "foo": 42 };
const value2 = { 
"foo": 42,
toString() {
return `foo is ${this.foo}`;
}
};
const value3 = { 
"foo": 42,
toString() {
return "Hello world";
}
};
console.log(value1 + ""); //default `toString()` method of objects
console.log(value2 + "");
console.log(value3 + "");

同样的事情发生在代码的最后部分:

window+''

这将:

  1. 触发转换为字符串
  2. window上调用toString方法
  3. 使用toString=xx覆盖
  4. 调用x函数
  5. 将全局错误处理程序设置为仅为alert(onerror=alert) and immediately throws an error (抛出1337`(
  6. 调用全局错误处理程序

为什么省略window+''不会引发错误

希望从上面可以清楚地看到,但要直接解决这个问题,需要代码来引发之前定义的整个反应链

以下是完整的代码,为了清晰起见,提供了解释和格式:

//create a function
window.x = x => {
onerror = alert; //changes the global error handler
throw 1337       //throws an error to trigger the error handler
};
//overwrite the `toString` method of `window` so it always throws an error
window.toString = window.x; 
//implicitly call `window.toString()` by performing a string concatenation
window + '';

最新更新