一开始我也有疑问,为什么 ++[[]][+[]]+[+[]]='10' ?
不得不信,于是我们要慢慢的分析:
[] 有两个作用:
1. 数组
2. 访问属性和方法
例子:
- [1, 2, 3, 4] // 数组
- "abc" [0] // 属性
- [1,2]["length"] // 方法
1. 创建数字
2. 将两个值相加
3. 连接字符串
4. 创建字符串
operand + operand = result
1. 如果操作符数中有一个对象,它将转换为原始值 (
、
- string
或
- number
)
- boolean
2. 如果操作符数中有一个字符串,第二个操作数将转换成字符串,并且连接在一起转换成一个字符串
3. 在其它情况之下,两个操作数转换为数字并且将执行加法运算
其中,对象转换的规则:
1. 如果对象类型是一个
,可以使用
- Date
方法
- toString()
2. 在其它情况下使用
方法,它将返回一个原始值
- valueOf()
3. 如果
方法不能将它返回一个原始值,可以使用
- valueOf()
方法。而这种情况大部分情况下都会发生
- toString()
例子:
- // 数字和字符串
- var result = 1 + "5"; // "15"
- // 数字和数组
- var result = [1, 3, 5] + 1; // "1,3,51"
- // 数字和布尔值
- var result = 10 + true; // 11
- // 数字和对象
- var result = 15 + {}; // "15[object Object]"
- // 数字和null
- var result = 8 + null; // 8
- // 字符串和null
- var result = "queen" + null; // "queennull"
- // 数字和undefined
- var result = 12 + undefined; // NaN
下面这张图是两个变量相加的类型结果:
一元正号运算符(unary plus operator)位于其操作数前面,计算其操作数的数值,如果操作数不是一个数值,会尝试将其转换成一个数值。它可以将字符串转换成整数和浮点数形式,也可以转换非字符串值
,
- true
- false
- 和
。小数和十六进制格式字符串也可以转换成数值。负数形式字符串也可以转换成数值(对于十六进制不适用)。如果它不能解析一个值,则计算结果为 NaN。
- null
例子:
- + 3 // 3
- + "3" // 3
- + true // 1
- + false // 0
- + null // 0
- + [] // 0
递增运算符(increment operator) 为其操作数增加 1,返回一个数值。
首先把这个表达式拆分开来,如:
- ++[[]][+[]]
- +
- [+[]]
由上面的基础分析可知, +[] === 0 是完全正确的, 故我们可以简化如下:
- ++[[]][0]
- +
- [0]
[[]][0] 返回内部数组 ([])。但是由于语言规范, [[]][0] === [] 是不正确的,因此我们暂时用 A 来代替里面的数组。
++[[]][0] == A + 1, 因为 ++ 的意思是 "+1"。
++[[]][0] === +(A + 1);这是一个数值,因为递增(++)返回的永远都是一个数值
因此,表达式可以简化如下:
- +([] + 1)
- +
- [0]
由上面的基础符号分析可以简化表达式如下:
- 1// 参考+在操作数前面+
- "0"// 参考两个变量相加的对象转换规则
故最终结果为'10'。
上面只是一个简单的例子,其实用这些字符串是可以写出真正有用的代码的,例如:
- (![] + [])[ + !+[]] + (![] + [])[!+[] + !+[]] + ( !! [] + [])[!+[] + !+[] + !+[]] + ( !! [] + [])[ + !+[]] + ( !! [] + [])[ + []] + (![] + [][(![] + [])[ + []] + ([![]] + [][[]])[ + !+[] + [ + []]] + (![] + [])[!+[] + !+[]] + ( !! [] + [])[ + []] + ( !! [] + [])[!+[] + !+[] + !+[]] + ( !! [] + [])[ + !+[]]])[!+[] + !+[] + [ + []]] + [ + !+[]] + ( !! [] + [][(![] + [])[ + []] + ([![]] + [][[]])[ + !+[] + [ + []]] + (![] + [])[!+[] + !+[]] + ( !! [] + [])[ + []] + ( !! [] + [])[!+[] + !+[] + !+[]] + ( !! [] + [])[ + !+[]]])[!+[] + !+[] + [ + []]] // alert(1)
可以在此生成想要的代码:http://www.jsfuck.com/
看着一些字符串可以执行,想必大家都有疑虑,用在哪些地方呢?
由于这样的代码属于混淆代码,不容易被识别,我们可以用在账户的安全校验上,比如,可以在 web 端账户登陆之前从后端拿到一段这样的可执行代码,将执行结果写入 cookie、token 或者 ajax 请求里,这样可以防止一部分黑产用工具刷接口来获取数据。
由于黑产现在采用的工具都是易语言写的。基于 winhttp.dll 和 winInet.dll 的,不具备 js 引擎,所以如果 web 端在提交登陆之前获取并执行后端的一段这样的代码,一来可以以混淆的代码使得黑产不容易看懂,二来如果黑产想破解的话,就需要一个 js 引擎或者无头浏览器,其成本是很高的。
用于安全上只是其中的一个例子,聪明的你可能还有更好的使用场景,不妨分享出来。
Addition (+):https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators
jsFuck: https://github.com/aemkei/jsfuck
JavaScript addition operator in details: https://rainsoft.io/javascriptss-addition-operator-demystified/
Why does ++[[]][+[]]+[+[]] return the string "10"?:https://stackoverflow.com/questions/7202157/why-does-return-the-string-10
来源: http://www.cnblogs.com/WeiRuifeng/p/7113755.html