underScore专题-字符串逃逸,防止XSS攻击

什么是XSS攻击?

举一个例子:页面中有一个input框,我们需要把用户输入的内容展示在页面中,具体代码如下:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        input {
            width: 200px;
            height: 30px;
            border-radius: 4px;
            border: 1px solid gray;
        }
    </style>

</head>

<body>
    <input id='btn' type="text">
    <button id="sub" type="submit">提交</button>
    <div id='content'></div>
</body>
<script>
    var inp = document.getElementById('btn');
    var sub = document.getElementById('sub');
    var content = document.getElementById('content')
    sub.addEventListener('click', function() {
        content.innerHTML = inp.value
    })
</script>
<script src="underScore.js"></script>
<script>
</script>

</html>

如果用户输入的是脚本呢?

<a href="javascript:alert(1)">攻击</a>

点击攻击,页面会出现一个弹框

这里加入的js代码可以顺利的执行,这样就很危险了,看下面的代码:

<img src=@ onerror='var s=document.createElement("script");s.src="xss.js";document.body.appendChild(s);' />

一份意外的js文件被引入,试想,如果这里是个绝对路径,里面是提前编辑好的js代码,这样就可以在你的页面上为所欲为,包裹回去cookie,用你的身份登陆网页,获取用户信息等等。总之,就是很危险。


为了防止这种情况的发生,我们可以将网址上的值取到后,进行一个特殊处理,再赋值给 DOM 的 innerHTML。

underScore源码中,把一些不安全的字符都转变成了字符串实体。

什么是字符串逃逸?

就是把一些不安全的字符都转变成了字符串实体。

下面列举了一些字符串对应的字符串实体:


    // List of HTML entities for escaping.
    var escapeMap = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#x27;',
        '`': '&#x60;'
    };

当用户输入的字符串中包含这里的key是,就把它转换为对象的value。这样说大家可能不太明白是在干什么?为什么这样转换就能防止XSS攻击了,别急,往下看:

把刚刚的代码输入替换一下:

&lta href="javascript:alert(1)"&gt攻击&lt/a&gt

把尖括号替换成字符串实体后,看页面会输出什么?页面输出了输入框的内容,但不会把输入字符串当成标签输出,是以字符串的形式输出的,这样就无法再注入js代码了,因为到页面都会被转换为字符串,这样就安全多了。

 

underScore内部的escape函数就做了这样的事情:

    // Functions for escaping and unescaping strings to/from HTML interpolation.
    function createEscaper(map) {
        var escaper = function(match) {
            return map[match];
        };
        // Regexes for identifying a key that needs to be escaped.
        var source = '(?:' + keys(map).join('|') + ')';
        var testRegexp = RegExp(source);
        var replaceRegexp = RegExp(source, 'g');
        return function(string) {
            string = string == null ? '' : '' + string;
            return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
        };
    }
    var escape = createEscaper(escapeMap);

testRegexp正则写成字面量就是这样的: 

var str = '<a href="javascript:alert(1)">攻击</a>'
var testRegexp = /(?:&|<|>|"|'|`)/;
console.log(testRegexp.test(str)) // true
var str = '防止攻击`设计`'
var testRegexp = /(?:&|<|>|"|'|`)/;
console.log(testRegexp.test(str)) // true

这里(?:pattern)是非捕获分组,不加这个也可以实现功能,但是会影响性能,推荐一本书《JavaScript正则表达式迷你书》

所以这里加了非捕获分组,不去捕获匹配的内容。

正则如果不加全局匹配,只会匹配到一个后停止:

    var str = '防止攻击`设计`'
    var testRegexp = /(?:&|<|>|"|'|`)/;
    str.replace(testRegexp, function(match) {
        console.log(match) // `
    })

这里就匹配到了第一个'`',所以需要给这个正则加全局匹配,至于为什么不直接使用使用全局匹配,估计也是考虑性能的问题,全局匹配肯定要比非全局匹配消耗性能。

    var str = '防止攻击`设计`'
    var testRegexp = /(?:&|<|>|"|'|`)/g;
    str.replace(testRegexp, function(match) {
        console.log(match) // ` 
    })

换成全局的,就会打印两次:

最后的使用,是需要调用这个函数,处理用户输入的字符串就可以有效的防止XSS攻击了。 

 content.innerHTML = _.escape(inp.value)

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值