• 从++[[]][+[]]+[+[]]='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

  • 相关阅读:
    Java入门
    Java入门
    Java入门
    Java入门
    Java入门
    Java入门
    Java入门
    random库的使用
    程序的控制结构
    数据类型
  • 原文地址:https://www.cnblogs.com/WeiRuifeng/p/7113755.html
Copyright © 2020-2023  润新知