【安全】web前端安全基础浅谈
你觉得你的个人信息安全吗?你有试过网上点外卖后就陆续收到各种的传销电话吗?你有试过账号被盗用然后发布各种的广告信息吗?互联网的发展给大众带来了很多的便利,我们可以足不出户就进行购物、充值游戏、转账汇款理财等各种操作。但便利同时伴随着风险,个人资料、私密账户等都有可能被暴露在网络之中。

要怎么保障我们用户的个人信息财产,web安全成为了一个重要的课题。我今天主要想跟大家探讨的是web前端安全。根据数据显示,截至2015年有80%的App全部或部分基于HTML5。这意味着大部分App的内容都将是以网页的形式呈现,互联网很大程度上是由html+css+js构成,因此web前端安全可以说是web安全的重要的分支。
前端安全目前主要可以划分为三大类:XSS(跨站脚本攻击)、CSRF(跨站请求伪造)和界面操作劫持,下面我们将结合实际场景分析攻击与防御。
一、XSS(跨站脚本攻击)
XSS可以算是客户端脚本安全中 的头号大敌,曾多次位于 OWASP TOP 10 威胁的榜首。跨站脚本攻击是Cross Site Scripting,但为了与层叠样式表css区分所以缩写为 XSS,它的重点在于脚本而不是跨站,攻击者往往通过插入恶意的Script代码对用户进行攻击,具体的攻击过程如图所示。

XSS漏洞非常广泛,不过并不是所有的漏洞都有危险或者利用价值,早起甚至一些大网站也很少在意这个漏洞,但是随着XSS的利益化与舆论化,XSS开始得到更多的关注。XSS可以分为非持久型攻击跟持久型攻击。顾名思义,非持久型xss攻击是一次性的,仅对当次的页面访问产生影响。
举个简单的例子:当我们在数据输入没有做严格控制的网站的搜索框里面[搜索结果是被放在 <div class=“result”> </div>],输入搜索内容为:
</div><script type=“text/javascript”>alert(‘xss attack')</script><div>
当我们搜索的时候,因为字符串整体会变成
<div class=“result”></div><script type=“text/javascript”>alert(‘xss attack’)</script><div></div>
因而js会被执行并弹出对话框:

当然一个弹出框并不能做些什么,但是实际的攻击中,alert()会被替换成一些恶意脚本[例如盗取用户cookie的脚本]或者第三方的脚本资源,就会为用户安全带来威胁。攻击者只需要把自己准备的url提供给用户点击,就能进行攻击。而这种整个过程一次反射,下次请求时需要再提交XSS代码的,就称为非持久性XSS攻击。非持久型xss攻击要求用户访问一个被攻击者篡改后的链接,用户访问该链接时,被植入的攻击脚本被用户游览器执行,从而达到攻击目的。
而持久性XSS攻击会把提交的代码存储在服务端,下次请求页面的时候就不用再进行提交。最为经典的例子就是留言板XSS,当我们提交一条包含XSS代码的留言存储到数据库,目标用户查看的时候那些内容就会从数据库查询并显示,从而触发执行。
我们了解了攻击的种类,那我们应该如何防御呢?下面的几条原则可能会帮到我们。
第一条是不要在页面中插入任何不可信数据,除非按相关原则进行了编码。首先我们假定一切的输入输出都可能是有害的,因为HTML里有太多的地方容易形成XSS漏洞,在html标签、标签里的属性、<script>标签甚至是css里都可以产生。
第二条是当我们不得不往页面中插入不可信数据的时候,我们应该作如下处理:
- 插入到HTML标签之间时,对这些数据进行HTML Entity编码
& –> &
< –> <
–> >
” –> "
‘ –> '
/ –> /
其中有两点需要特别说明的是: 不推荐将单引号( ‘ )编码为 ' 因为它并不是标准的HTML标签。需要对斜杠号( / )编码,因为在进行XSS攻击时,斜杠号对于关闭当前HTML标签非常有用。
- 将不可信数据插入到HTML属性里时,对这些数据进行HTML属性编码。假设HTML代码是这样的:
<div width=输入内容> …content… </div>, 攻击者可以构造这样的输入:x onmouseover=”javascript:alert(/xss attack/)”最后,在用户的浏览器里的最终HTML代码会变成这个样子:
<div width=x onmouseover=”javascript:alert(/xss attack/)”> …content… </div>
- 每当鼠标移动到这个div的时候,就会触发攻击的脚本。所以当往HTML属性(例如width、name、value属性)插入不可信数据值的时候,除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 &#xHH; (以&#x开头,HH则是指该字符对应的十六进制数字,分号作为结束符)。
可以使用ESAPI提供的函数进行HTML属性编码:String encodedContent = ESAPI.encoder().encodeForHTMLAttribute(request.getParameter(“input“));
但是当往HTML标签的事件处理属性(例如 onmouseover)里插入数据的时候,就不适用于本原则,应该进行javascript编码。
- 将不可信数据插入到script里的时候,或者是HTML标签属性里的事件处理时,
可以使用ESAPI提供的函数进行JavaScript编码:String encodedContent = ESAPI.encoder().encodeForJavaScript(request.getParameter(“input”));
- 一般我们都认为CSS只是负责页面的样式,但实际上也能带来很多攻击。因此我们应该只允许把不可信数据放入到CSS属性的值部分,并进行适当的编码。除此以外,最好不要在比如url, behavior,只能被IE认识的Expression属性允许执行JavaScript脚本等的地方插入不可信数据;
可以使用ESAPI提供的函数进行CSS编码:String encodedContent =ESAPI.encoder().encodeForCSS(request.getParameter(“input”));
- 将不可信数据插入到URL的时候,要特别注意的: 1) URL属性应该使用引号将值部分包围起来,否则攻击者可以很容易突破当前属性区域,插入后续攻击代码 2) 不要对整个URL进行编码,因为不可信数据可能会被插入到href, src或者其他以URL为基础的属性里,这时需要对数据的起始部分的协议字段进行验证,否则攻击者可以改变URL的协议,例如从HTTP协议改为DATA伪协议,或者javascript伪协议。
可以使用ESAPI提供的函数进行URL编码: String encodedContent = ESAPI.encoder().encodeForURL(request.getParameter(“input”));
- 针对富文本,我们可以使用XSS规则引擎对用户输入进行编码过滤,只允许用户输入安全的HTML标签,如
<b>,<i>,<p>等,对其他数据进行HTML编码。需要注意的是,经过规则引擎编码过滤后的内容只能放在<div>,<p>等安全的HTML标签里,不要放到HTML标签的属性值里,更不要放到HTML事件处理属性里,或者放到<SCRIPT>标签里。
二、CSRF(跨站请求伪造)
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。简单来说就是用户在登录某网站的状态下,访问了恶意网站,然后自动执行一串恶意代码,不知不觉地被攻击者冒充去访问了正常网站。
按照攻击方式分类,我们可以分为HTML CSRF攻击、JSON HiJacking攻击和Flash CSRF攻击。
HTML CSRF攻击是最普遍的一类,能够通过可以设置src/href等的标签发起一个get请求,如:
<link href=“”>
<img src=“”>
<meta http-equiv=“refresh” content=“0;url=”>
<iframe src=“”>
又譬如CSS样式中:
@import “”
background: url(“”)
而JSON HiJacking攻击是对AJAX相应中最常见的json数据类型进行的劫持攻击。一般来说,譬如要传输如下的数据
$data=array("username"=>"test",
"password"=>"test"
);
如果传输的数据在两个不同的域,譬如对于大的互联网公司,代表了A应用的A域名想获取代表B应用的B域名的数据时,由于在javascript里无法跨域获取数据,所以一般采取script标签的方式获取数据,传入一些callback来获取最终的数据。获取上面数据的时候可以使用userinfo={“username":"test","password":"test"}。但由于数据在两个完全不同的域里传输,如果缺乏有效地控制就会导致数据被泄露给第三方程序。
而FLASH CRSF攻击是涉及到Action script脚本来完成的,所以在这里我们就不详细展开说明。
对于CRSF攻击,目前最常用的几种防御策略如下:
-
检查HTTP Referer字段是否同域,因为一般情况下用户提交站内请求,referer的来源应该是站内地址,如果referer异常,我们就可以怀疑是否遭到了CRSF攻击。当然,这点对站内的攻击就显得有点无能为力了。
-
限制session cookie的生命周期,在一段时间后登录cookie会被自动销毁,再操作要进行重新登录,这能在一定成都上减少了被攻击的概率。
-
使用验证码,尤其是在付款交易等一些重要场景,使用这个方法能有效的阻断攻击。
-
使用一次性的token,这个经常应用于表单中,会随着表单提交并由服务器对其合法性进行验证,因为token的随机性,攻击者要得到这个token就比较难,因此攻击也就无法成功。
-
执行重要操作的时候需要进行额外的操作,在付款交易等涉及账户重要操作的情况下,要求用户进行该操作的密码验证,也是一种有效的方法。
三、界面操作劫持
界面操作劫持是一种基于视觉欺骗的会话劫持攻击,它会通过在网页可见输入的控件上覆盖一个不可见的iframe,当用户输入的时候会认为自己在操作可见的空间,而实际上被恶意劫持,从而在不知情的情况下被窃取敏感信息、篡改数据等。从技术上可以分为点击劫持、拖放劫持和触屏劫持三种,而它们基本都是通过透明层+iframe嵌套来实现的。
点击劫持我们可以通过这么一个例子来了解:
<style>#click{
width: 100px;
top: 20px;
left :20px;
position: absolute;
z-index: 1;
}#hidden{
height: 50px;
width: 120px;
position: absolute;
filter: alpha(opacity=50);
opacity: 0.5;
z-index: 2;
}
</style>
<input id=“click” value=“click here” type=“button”></input>
<iframe id=“hidden” src=“attack.html” scrolling=“no”></iframe>
当用户在页面中进行点击的时候,实际就点击了我们的隐藏iframe,从而跳转到别的网站。
而拖动劫持相对来说就比较复杂,因为可以拖放的内容再不断的增加,图片、链接等各种都是可以拖放的。它需要有dataTransfer对象存放需要传递的数据,还需要确定需要劫持的操作函数。
触屏劫持一般是在移动设备上实现,因为触摸屏微笑,所以在视觉欺骗上更加容易。当我们在看查找一个电视剧的时候,点击的查询按钮有可能实际上完成了一次网银交易的操作。
因为界面劫持是通过巧妙的视觉欺骗来实现的,所以在防御上面更为简单有效,只要我们使重要的会话的交互页面上不允许iframe嵌入,或者只允许同域iframe嵌入。
有趣的是,上面我们用到的token,在界面劫持的防御上也有大用处。譬如一个登录页面http://url/login?idtoken=0um2k9S,如果攻击者不能猜测到后面的数值,那么页面就无法被嵌入。
另外我们还可以使用javascript脚本对页面进行控制,让iframe无法被嵌入,这样的脚本称为Frame Busting脚本,示例如下:
<script>
if (top.location != self.location){
top.location = self.location;
}
</script>
top指代主体窗口对象,self指代当前窗口对象。如果判断两者有所不同,就将主体窗口地址设置为当前窗口地址,这能避免实际操作跟所见窗口不一致的情况。
网络攻防战是个大范畴,有人的地方就是江湖。在社会的发展和利益驱动下,更多的网络攻击跟安全漏洞都会被暴露并利用。了解攻击,实际上也是为了更好的了解如何防御,希望这篇文章能对你有所帮助。
浙公网安备 33010602011771号