从++[[]][+[]]+[+[]]='10'谈安全

一开始我也有疑问,为什么 ++[[]][+[]]+[+[]]='10' 

不得不信,于是我们要慢慢的分析:

分析基础符号

[]分析

[]有两个作用:

1. 数组

2. 访问属性和方法

例子:

[1,2,3,4]   // 数组
"abc"[0]     // 属性
[1,2]["length"]  // 方法

+运算符的作用

1. 创建数字
2. 将两个值相加
3. 连接字符串
4. 创建字符串

两个数相加

operand + operand = result

1. 如果操作符数中有一个对象,它将转换为原始值(stringnumberboolean)

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

下面这张图是两个变量相加的类型结果:

           

位于操作数之前(+x)

一元正号运算符(unary plus operator)位于其操作数前面,计算其操作数的数值,如果操作数不是一个数值,会尝试将其转换成一个数值。它可以将字符串转换成整数和浮点数形式,也可以转换非字符串值 truefalse  null。小数和十六进制格式字符串也可以转换成数值。负数形式字符串也可以转换成数值(对于十六进制不适用)。如果它不能解析一个值,则计算结果为 NaN。

例子:

+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

 

posted @ 2017-07-04 00:46  线流五里牌  阅读(1047)  评论(6编辑  收藏  举报