为什么(![] + [])[+ !! [] + []]产生“a”

时间:2010-01-20 09:17:22

标签: javascript security

我有兴趣了解JavaScript的内部结构。我试过阅读SpiderMonkeyRhino的来源,但是我的头脑很复杂。

我问的原因是:为什么会这样?

  • (![]+[])[+!![]+[]]生成"a"
  • (Å=[],[µ=!Å+Å][µ[È=++Å+Å+Å]+({}+Å)[Ç=!!Å+µ,ª=Ç[Å]+Ç[+!Å],Å]+ª])()[µ[Å]+µ[Å+Å]+Ç[È]+ª](Å)生成alert(1)

来源:http://sla.ckers.org/forum/read.php?24,32930,page=1

在该论坛上还有更多关于JavaScript奇怪的例子,我想从编程的角度来了解它在Web应用程序安全性方面的作用。

4 个答案:

答案 0 :(得分:16)

如果你想了解为什么那些奇怪的表达式会像他们一样工作,你可以打开firebug控制台并自己做实验。我做了,我得到![]false!![]true,将数组添加到布尔值(false+[]true+[])生成此值的字符串版本(false+[]="false")。

这样的表达归结为:

"false"["1"] 

这显然是“一个”

答案 1 :(得分:12)

为什么(![]+[])[+!![]+[]]会产生“a”

一步一步:在(![]+[])[+!![]+[]]中进行解析。第一位已经由artemb解释:[]是一个数组。否定它,![]计算为布尔值false - 这就是!在应用于非null或未定义的内容时的工作方式。再次如artemb所指出的那样,附加此+[]会强制将布尔值转换为字符串。那是因为+是一个字符串连接运算符。然后将布尔值false转换为其字符串表示形式"false"

然后,第二位[+!![]+[]]。首先,外部[]用于处理前面的字符串,我们刚刚将其作为一个字符数组等于"false"。通过在[]中放置一个整数索引,可以得到特定索引处的字符。剩下的就是+!![]+[] 这包括4件:+!![]+[]。首先评估!![]。我们已经看到![]是一个布尔false,所以在另一个!之前加上否定它,并产生true。接下来发生的事情是+中的+!![]被应用,并且通过应用+,它将布尔值true转换为数字表示,即1 (所以+true1)后面的+[]1产生"1"再次生成一个字符串,但它没有意义,更短的表达(![]+[])[+!![]]已生成a。追加+[]也不会造成伤害,结果表达式只是["1"]而不是[1]。我的预感是,当[]应用于数组时,[]内的任何内容都会被强制转换为数字,"1"会再次给1。所以无论哪种方式,+!![]+[]评估为1,最后表达式为:"false"[1],它说:从字符串"false"中获取索引1处的字符,并且因为默认情况下,数组从javascript中的0开始,这是"false"a的第二个字符。

答案 2 :(得分:2)

为什么(![] + [])[+ !! [] + []]产生“a”

  1. !expr - 在expr上调用ToBoolean并翻转布尔值。换句话说,当与not运算符一起使用时,诸如空数组之类的truthy值将产生错误。
  2. a + b - 两个表达式都通过内部ToPrimitive运行。如果结果值是字符串,则执行字符串连接。否则,基元将通过ToNumber运行并添加。对象的ToPrimitive(包含数组)将尝试toString和valueOf。 Array.prototype.toString充当没有参数的调用连接。因此,![] + [] = false + "" = "false"
  3. !![] == true,一元加号运算符将表达式转换为数字,因此1。同样,数组转换为""所以+!![]+[] == "1"
  4. 表达式归结为("false")["1"] == "a"
  5. 另一种表达方式可以用类似的方式归结。它使用unicode字符串来搞砸它并且它更长,但就像直接“解析”一样。

答案 3 :(得分:1)

我建议您获取并阅读:

  • ECMAScript标准(ECMA 262),第5版
  • Adob​​e文档名为“AVM 2 overview”,它解释了AVM2虚拟机的体系结构,Adobe Flash及其ActionScript在其上运行。