前言
几个月前碰巧遇到人生第一个安全问题,在负责的输入部分没有做非法字符验证,于是随便写了个alert('hahaha')
,导致保存后再次查看输入详情时,立马弹出对话框。究其缘由,是前端没有做字符验证,服务端也没有做验证,最后输入端采用jsp的后端渲染方式,于是一点开详情,就爆炸了。春节前有空就看了看《白帽子讲web安全》。
XSS跨站脚本攻击
XSS攻击,通常指黑客通过“HTML注入”篡改网页,插入恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。重点就是篡改网页。
前面提到的例子,其实就是XSS,看着好像没有什么大问题,但是如果把输入部分的alert('hahaha')
改成一段数据发送的代码,将cookie等重要信息发送到其他地址,那危害就十分显著了。
根据其效果可以分为:
- 反射型XSS:将用户操作“反射”给浏览器,如诱使用户点击恶意连接,也叫做“非持续性XSS”;
- 存储型XSS:将用户输入的数据“存储”在服务器。前面例子也就是存储型XSS了,也叫“持久型XSS”;
- DOM Based XSS:效果上也是反射型,只是通过修改DOM形成XSS。
XSS攻击
常见的XSS攻击有Cookie劫持
,后台对权限的验证是基于id的,而这个id正是在cookie里面。后台并不知道访问者是张三还是李四,只要请求里面拥有证明是张三的cookie,那访问者就是张三,这个id就如同张三房间的门禁卡,而Cookie劫持
就是获取这个门禁卡。通过XSS攻击,将当前域cookie发送出去。黑客只要有这个cookie就可以轻松登陆。
对Cookie劫持
,很多时候只要在Set-Cookie
的时候给关键Cookie加上HttpOnly
的标识,这样就无法通过Javascript读取Cookie了,该Cookie只会随请求头一起发出去。
当然对于前端更熟悉应该是GET/POST请求,正常使用就是按照接口定义发送请求就好了。同样的黑客也可以通过反射型XSS/DOME Based XSS
的方式诱使用户点击来达到目的,比如让链接成为接口请求的url。
文中还提到几个小技巧,有些已经过时了,有些还是值得注意的:
<base>
标签可以重定义页面上使用相对路径的hosting地址,从而将访问的地址切到黑客准备的地址上。window.name
,window.name是具有跨域效果的,这就使得其可以用来跨页面传递数据,这个数据可以是Cookie,亦或者是id什么的。
XSS防御
最常见的防御莫过于HttpOnly
,用以解决XSS后的Cookie劫持,如果连Javascript都读取不到Cookie,只有请求的时候才会带上,那岂不是完美了。
当然HttpOnly
并非解决XSS的,而是降低XSS后的损失。上文提到的三种XSS,其实都有个共性,由于同源策略,不会因为你浏览B页面,而在不同域/protocol的A页面上产生XSS,那XSS要如何产生呢?
没有非法的输入,就没有伤害,这些XSS的形成都是从输入开始的,比如反射型XSS,常见于有用户交互的地方,比如搜索框,可以检查搜索框输入处是否有做输入检查,比如:http://xxx/Discuz7.2/upload/ajax.php?infloat=yes&handlekey=123);alert(/Hacked by qiqi/);//
只是访问url,但是由于没有检查输入,导致alert(/Hacked by qiqi/)
被执行了,这不就实现脚本加载了,接下来只要诱骗用户点击就好了。
对于存储型XSS更是如此,尤其是注册、留言板、添加数据等等这些有输入存储的地方,都可能造成XSS攻击。在XSS的防御上,输入检查一般是检查用户的输入数据有没有一些特殊字符如尖括号“<”、“>”等。对于电话号码或者银行账号这些有特殊规则的倒是可以不用如此检查。
除了输入检查,还有就是输出检查,可以使用编码或转义的方式来防御XSS攻击。这样就是后端渲染直接将含有脚本代码输出的时候,也因为存在编码转义JavascriptEncode/HtmlEncode,不能直接执行。
CSRF跨站点请求伪造
CSRF就是跨站点请求伪造,实现起来也是很简单的,在一个诈骗页面里面执行正常页面的接口。因为此时此刻用户已经打开登陆过正常页面A了,如果诱使用户打开诈骗页面,并诱使其在诈骗页面里面点开新Tag页面或者iframe,请求A的接口,这个时候请求头是带有用户A页面的Cookie的,也就是可以得到后台认证,从而实现请求。
这种请求的方式不仅仅限制与GET,还可以用POST,form表单的形式请求。
CSRF的防御
在项目中用Node.js做中间层的时候,采用的就是Egg.js,而egg.js开始用着还好,后面有POST表单Form请求的时候,经常遇到Node.js后台提示invalid CSRF TOKEN
,当时就觉得这个CSRF很奇怪了,听都没有听过。虽然官方文档说的很仔细了,但是时间紧迫,实在不知道怎么解决了,只能在配置文件里面,将所有的CSRF
验证关闭。从而实现正常请求。现在回想过来,也是觉得神奇。
回头看看CSRF防御,首先是Referer的问题,只有Referer正确才能说明请求来自正常页面,而非黑客准备的页面。好像这样就能克服CSRF伪造的问题了,但是请求中referer其实不是实时都有的。于是需要另外一个思路CSRF Token
:
CSRF能够实现的根源在于所有的请求参数黑客都能猜中,能正常访问接口。那如果我们在每次请求的时候,都加入一个验证用的token,让token与Cookie里面的csrfToken配对,如果正确就是正常页面发送的请求,否之,则不是,这样黑客不就无招可使了?
黑客是可以发送正常页面的请求,但是由于同源策略的问题,诈骗页面是无法获取到正常页面的cookie的,虽然请求正常页面的接口时,请求头带有正常页面的Cookie,但是请求参数里面却没有csrfToken,因为csrfToken需要从正常页面的cookie里面获取到呀~~
ClickJacking点劫持
点劫持是一种视觉上的欺骗手段。攻击者通过一个透明、不可见的iframe覆盖在一个网页上面,让后诱使用户操作点击该iframe。如下图所示
由此衍生出来的还有图片覆盖,就是替换图片,添加a标签,指向其他页面。还有拖拽劫持等等方式,这些方式赖以生存的唯一点就是利用iframe来进行视图欺骗。所以防御方法就是禁止iframe跨域,当然现代浏览器都是禁止的。
其他
文中还提到了服务端应用安全,包括常见的SQL注入问题、文件上传漏洞、加密问题和PHP安全,但是举的例子都是和PHP结合的,由于PHP并不熟悉,所以这里就不介绍了。
文中介绍内容还是很基础的,基本就是科普一下,如果想要更深入了解可以看看i春秋,还有渗透测试,渗透工具之类的。