原文出处: 淘宝UED - lorrylockie html
先后端分离模式下的安全解决方案
前言
在先后端分离的开发模式中,从开发的角色和职能上来说,一个最明显的变化就是:以往传统中,只负责浏览器环境中开发的前端同窗,须要涉猎到服务端层面,编写服务端代码。而摆在面前的一个基础性问题就是如何保障Web安全?前端
本文就在先后端分离模式的架构下,针对前端在Web开发中,所遇到的安全问题以及应对措施和注意事项,并提出解决方案。node
跨站脚本攻击(XSS,Cross-site scripting)是最多见和基本的攻击Web网站的方法。攻击者能够在网页上发布包含攻击性代码的数据,当浏览者看到此网页时,特定的脚本就会以浏览者用户的身份和权限来执行。经过XSS能够比较容易地修改用户数据、窃取用户信息以及形成其它类型的攻击,例如:CSRF攻击。git
预防XSS攻击的基本方法是:确保任何被输出到HTML页面中的数据以HTML的方式进行转义(HTML escape)。例以下面的模板代码:github
1
|
<textarea name="description">$description</textarea>
|
这段代码中的$description
为模板的变量(不一样模板中定义的变量语法不一样,这里只是示意一下),由用户提交的数据,那么攻击者能够输入一段包含”JavaScript”的代码,使得上述模板语句的结果变成以下的结果:ajax
1
2
3
|
<textarea name="description">
</textarea><script>alert('hello')'</script>
</textarea>
|
上述代码,在浏览器中渲染,将会执行JavaScript代码并在屏幕上alert hello。固然这个代码是无害的,但攻击者彻底能够建立一个JavaScript来修改用户资料或者窃取cookie数据。express
解决方法很简单,就是将$description
的值进行html escape,转义后的输出代码以下json
1
2
3
|
<textarea name="description">
</textarea><script>alert("hello!")</script>
</textarea>
|
以上通过转义后的HTML代码是没有任何危害的。后端
对数据进行转义有如下几种状况和方法:浏览器
中途岛内部使用KISSY xtemplate做为模板语言。
在xtemplate实现中,语法上使用两个中括号( {{val}}
)解析模板数据, ,默认既是对数据进行HTML转义的,因此开发者能够这样写模板:
1
|
<textarea name="description">{{description}}</textarea>
|
在xtemplate中,若是不但愿输出的数据被转义,须要使用三个中括号({{{val}}}
)。
开发者能够在Node.js程序或者模板中,直接调用Midway提供的HTML转义方法,显示的对数据进行转义,以下:
方法1:在Node.js程序中对数据进行HTML转义
1
2
3
4
|
var
Security= require('midway-security');
//data from server,eg {html:'</textarea>',other:""}
data
.html =Security.escapeHtml(data.html);
xtpl
= xtpl.render(data);
|
方法2:在模板中对HTML数据进行HTML转义
1
|
<textarea name="description">Security.escapeHtml({{{description}}})</textarea>
|
注意:只有当模板内部没有对数据进行转义的时候才使用Security.escapeHtml进行转义。 不然,模板内部和程序会两次转义叠加,致使不符合预期的输出。
推荐:若是使用xtemplate,建议直接使用模板内置的{{}}
进行转义; 若是使用其余模板,建议使用Security.escapeHtml
进行转义。
你可能会想到:“其实我就是想输出富文本,好比一些留言板、论坛给用户提供一些简单的字体大小、颜色、背景等功能,那么我该如何处理这样的富文原本防止XSS呢?”
Midway中提供了richText方法,专门用来过滤富文本,防止XSS、钓鱼、cookie窃取等漏洞。
有一个留言板,模板代码可能以下:
1
2
3
|
<div class="message-board">
{{{message}}}
</div>
|
由于message是用户的输入数据,其留言板的内容,包含了富文本信息,因此这里在xtemplate中,使用了三个大括号,默认不进行HTML转义;那么用户输入的数据假如以下:
1
|
<script src="http://eval.com/eval.js"></script><span style="color:red;font-size:20px;position:fixed;">我在留言中</span>
|
上述的富文本数据若是直接输出到页面中,必然会致使eval.com站点的js注入到当前页面中,形成了XSS攻击。为了防止这个漏洞,咱们只要在模板或者程序中,调用Security.richText方法,处理用户输入的富文本。
调用方法与escapeHtml相似,有以下两种方式
方法1: 直接在Node.js程序中调用
1
2
|
message
=Security.richText(message);
var
html = xtpl.render(message)
|
方法2: 在模板中调用
1
2
3
|
<div class="message-board">
Security.richText({{{message}}})
</div>
|
经过调用Security的richText方法后,最终的输出以下:
1
2
3
|
<div class="message-board">
<span style="color:red;font-size:20px;">我在留言中</span>
</div>
|
能够看出,首先:会形成XSS攻击的script
标签被直接过滤掉;同时style标签中CSS属性position:fixed;
样式也被过滤了。最终输出了无害的HTML富文本
除了在页面的模板中可能存在XSS攻击以外,在Web应用中还有其余几个途径也可能会有风险。
一个页面若是找不到,系统可能会报一个404 Not Found的错误,例如:http://localhost/page/not/found
1
2
|
404
NotFound
Page
/page/not/found does not exsit
|
很显然:攻击者能够利用这个页面,构造一个相似这样的链接,http://localhost/%3Cscript%3Ealert%28%27hello%27%29%3C%2Fscript%3E
,并引诱受害者点击 ;假如出错页面未对输出变量进行转义的话,那么链接中隐藏的 <script>alert('hello')</script>
将会被执行。
在express中,发送一个404页面的方法以下
1
|
res
.send(404,'Sorry,we don\'t find that!')
|
这里就须要开发者注意错误页面(404或者其余错误状态)的处理方式。若是错误信息的返回内容带有路径信息(其实更准确的讲,是用户输入信息),就必定要进行escapeHtml了。
后续,错误处理的安全机制,会在Midway框架层面中完成。
Midway默认支持xtemplate模板,但未来也有可能支持其余模板:如jade、mustache、ejs等。目前在主流模板中,都提供了默认转义和不转义的输出变量写法,须要开发者特别留意其安全性。
除了对页面中输出的普通数据和富文本数据,一些场景中也还包含其余可能须要转义的状况,Midway提供了以下几个经常使用的转义方法,供开发者使用:
例子以下
1
2
3
4
5
6
|
var
jsonText ="{\"<script>\":\"<script>\"}";
console
.log(SecurityUtil.escapeJson(jsonText));// {"<script>":"<script>"}
var
jsonText ="{\"你好\":\"<script>\"}";
console
.log(SecurityUtil.escapeJsonForJsVar(jsonText));//{\"\u4f60\u597d\":\"<script>\"}
var
str ="alert(\"你好\")";
console
.log(SecurityUtil.jsEncode(str));// alert(\"\u4f60\u597d\")
|
名词解释: 表单:泛指浏览器端用于客户端提交数据的形式;包括a标签、ajax提交数据、form表单提交数据等,而非对等于HTML中的form标签。
跨站请求伪造(CSRF,Cross-site request forgery)是另外一种常见的攻击。攻击者经过各类方法伪造一个请求,模仿用户提交表单的行为,从而达到修改用户的数据或执行特定任务的目的。
为了假冒用户的身份,CSRF攻击经常和XSS攻击配合起来作,但也能够经过其它手段:例如诱使用户点击一个包含攻击的连接。
解决CSRF攻击的思路分以下两个步骤
一个正经常使用户修改网站信息的过程以下
而一个CSRF攻击则不会走这条路线,而是直接伪造第2步用户提交信息
只要可以区分这两种状况,就可以预防CSRF攻击。那么如何区分呢? 就是对第2步所提交的信息进行验证,确保数据源自第一步的表单。具体的验证过程以下:
这样,若是攻击者伪造要修改的信息并提交,是没办法直接访问到session的,因此也没办法拿到实际的token值;请求发送到服务端,服务端进行token校验的时候,发现不一致,则直接拒绝这次请求。
若是服务端不接受GET方式提交的表单数据,那么将会给攻击者带来很是大的难度;由于在页面上构造一个a标签href属性或者img标签src属性来构造一个请求是很是容易的,可是若是要POST提交,就必需要经过脚本才能够实现。
由于Midway不涉及到淘宝分布式session及token校验这一层面逻辑,因此在Midway框架中,只将token在server和客户端之间进行转发,自己不作实际的校验工做。流程以下:
后续:在Midway中,Node.js和淘宝的分布式session对接后,能够考虑在Midway这一层自动进行token校验;毕竟安全校验越早进行,成本也会更低。
建议:在Midway中,能够判断是否request中有token的值,若是一个修改操做,没有token,能够直接在Midway层认为是不安全的,将请求丢弃掉。
关于常见的Web安全问题,还有以下几种,这里只作一些简介,后续会持续继承到Midway framework中。
关于cookie的安全问题,以前WebX已经有较好的解决方案;这次Midway不负责cookie的设置和校验等工做,只负责转发到WebX层面进行check
XSS等注入性漏洞是全部漏洞中最容易被忽略,占互联网总攻击的70%以上;开发者编写Node.js代码时,要时刻提醒本身,永远不要相信用户的输入。
好比以下几个例子。
var mod = fs.readFileSync('path');
若是path来源于用户输入,那么假设用户输入/etc/password
,则会读取到不该该读取的内容,形成密码泄漏风险var result = eval(jsonVal);
必定要确保jsonVal是json,而不是用户的输入先后端分离模式下,可让传统的前端开发人员开始编写后端代码,虽然从架构上讲,只负责模板这一层,但也会接触大量的后端代码;因此安全对于前端来讲,这是一个不小的挑战。