安全漏洞整改系列(二)
本篇是之前安全漏洞整改系列(一)的延续,也是终结篇,希望通过这两篇内容带给大家一些关于安全问题的体验和重视,不至于漏洞真正来临的时候手忙脚乱,就像前几天的log4j2一夜间让多少程序员又白了头,宽了衣带。
图片拍摄于西安太奥海洋馆
问题4:反射性xss存储
漏洞等级:高危
漏洞详情:存在xss漏洞,可以将恶意脚本执行到合法网站或者Web应用程序中,漏洞验证截图如下
漏洞危害:攻击者可以伪造网站链接,诱导他人点击,获取关键信息,如session窃取等。
说下这里的tabs2是做什么用的,这是一个Controller方法,对应的视图是一个velocity页面,Controller解析url参数进行一些处理返回给velocity页面。
Controller setAttribute("tabsParams",tabsParams); velocity <script> tabsParams= "$!tabsParams"; </script>
这个访问链接为什么会造成xss呢?
tabs2?;9805";;alert(document.cookie);"9688
velocity是一种模板引擎,最终返回给浏览器的还是html,我们看下最终生成的产物是什么样的。
<script> tabsParams = "&;9805";;alert(document.cookie);"9688=null"; </script>
看到这儿其实已经很明显了,;9805";;alert(document.cookie);"9688这一串内容前后两个双引号很巧妙的破坏了原来js的语义,本来只是一个普通的赋值语句,现在却变成了三条js语句,其中就包含那条邪恶的alert(document.cookie);
解决办法和之前很相似,对返回给前端的内容做充分转义,这里我使用的是org.owasp.encoder这个转义库,这个转义库针对多种上下文提供了很好的支持,使用的时候要区别对待,不能一概而论,否则会误杀。
Encode.forJavaScript(tabsParams);
对比看下,转义前后返回到前端的内容有何区别
转义前:
<script> tabs = "&;9805";;alert(document.cookie);"9688=null"; </script>
转义后:
tabs = "\x26;9805\x22;;alert(document.cookie);\x229688=null";
可以看到字符串被转义成了\x22,保护了原有的执行语义。
问题5:sql注入
漏洞等级:高危
漏洞详情:***/findPage接口存在SQL注入漏洞
漏洞危害:攻击者能够直接获取数据库操作权限,查看用户信息下载用户数据
findPage接口是一个分页接口,会接收一个sortField字段,这个sortField最终会反映到SQL语句中,起到动态调整排序列的效果。
比如以下SQL语句:
select * from user order by ${sortField}
${sortField}会被替换为传入的值,比如age、name这些正常的值,还有一些非正常的值,比如1 and (SELECT 1271 from (select (sleep(10)))Ssvo),看下最后这个替换完会呈现什么效果
SELECT * FROM test.user ORDER BY 1 AND (SELECT 1271 FROM (SELECT (SLEEP(10))) Ssvo)
最终执行的效果就是睡眠10s,想象下如果有成百上千个sleep在数据库执行,我们的业务系统会怎样。
聪明的你也许会说为什么不用预编译解决这种SQL注入呢,在这种场景之下其实是不能使用预编译的,order by后面需要一个确切的列名,如果是问号,那SQL解析阶段就会报语法错误,那有什么办法可以解决呢?
1.控制sortField为一个有限的集合,不要直接替换到SQL中,增加一层判断
if(sortField.equals("age")){ sql.replace(${sortField},"age"); }else if(sortField.equals("name")){ sql.replace(${sortField},"name"); }else { throw Exception("不支持的排序列"); }
2.对sortField执行过滤,限制只能是数字、字母、下划线
sortField.replace("[^a-zA-Z0-9_\s+]", "");
问题6:任意用户密码重置
漏洞等级:高危
漏洞详情:忘记密码时,先输入一个已经存在的手机号,点击发送短信验证码,攻击者随意输入6位字符,点击下一步,拦截响应包,篡改为true,进入到设置新密码页面
漏洞危害:重置任意用户密码
下面是目前重置密码的流程
1.验证手机号码是否存在;
2.后台发送验证码;
3.校验验证码是否正确;
4.修改新密码;
这个漏洞也是一些多步操作容易遗漏的,后面的环节没有在后台校验前面步骤的合法性,就拿这个场景来说,真正修改密码时应该后台再校验前一步验证码的状态,防止攻击者绕过前端校验。
改造后的流程如下:
1.验证手机号码是否存在;
2.后台发送验证码;
3.校验验证码是否正确,并记录验证码状态;
4.后台校验前一步验证码状态,如果合法,修改新密码
推荐阅读
1.阿里技术-如何避免出现SQL注入漏洞
https://mp.weixin.qq.com/s/mP49OCkwqSnamtop0cChdQ
安全问题无小事,以上两篇是我近期负责整改的一些安全漏洞的记录,希望能给大家带来些许帮助,后续如果还有这方面的内容会继续输出,我对安全领域也是小白一枚,以上内容如有纰漏,欢迎指正。