安全漏洞整改系列(二)
本篇是之前安全漏洞整改系列(一)的延续,也是终结篇,希望通过这两篇内容带给大家一些关于安全问题的体验和重视,不至于漏洞真正来临的时候手忙脚乱,就像前几天的log4j2一夜间让多少程序员又白了头,宽了衣带。
图片拍摄于西安太奥海洋馆
问题4:反射性xss存储
漏洞等级:高危
漏洞详情:存在xss漏洞,可以将恶意脚本执行到合法网站或者Web应用程序中,漏洞验证截图如下
漏洞危害:攻击者可以伪造网站链接,诱导他人点击,获取关键信息,如session窃取等。
说下这里的tabs2是做什么用的,这是一个Controller方法,对应的视图是一个velocity页面,Controller解析url参数进行一些处理返回给velocity页面。
1 2 3 4 5 6 7 | Controller setAttribute( "tabsParams" ,tabsParams); velocity <script> tabsParams= "$!tabsParams" ; </script> |
这个访问链接为什么会造成xss呢?
1 | tabs2?;9805 ";;alert(document.cookie);" 9688 |
velocity是一种模板引擎,最终返回给浏览器的还是html,我们看下最终生成的产物是什么样的。
1 2 3 | <script> tabsParams = "&;9805" ;;alert(document.cookie); "9688=null" ; </script> |
看到这儿其实已经很明显了,;9805";;alert(document.cookie);"9688这一串内容前后两个双引号很巧妙的破坏了原来js的语义,本来只是一个普通的赋值语句,现在却变成了三条js语句,其中就包含那条邪恶的alert(document.cookie);
解决办法和之前很相似,对返回给前端的内容做充分转义,这里我使用的是org.owasp.encoder这个转义库,这个转义库针对多种上下文提供了很好的支持,使用的时候要区别对待,不能一概而论,否则会误杀。
1 | Encode.forJavaScript(tabsParams); |
对比看下,转义前后返回到前端的内容有何区别
转义前:
1 2 3 | <script> tabs = "&;9805" ;;alert(document.cookie); "9688=null" ; </script> |
转义后:
1 | tabs = "\x26;9805\x22;;alert(document.cookie);\x229688=null" ; |
可以看到字符串被转义成了\x22,保护了原有的执行语义。
问题5:sql注入
漏洞等级:高危
漏洞详情:***/findPage接口存在SQL注入漏洞
漏洞危害:攻击者能够直接获取数据库操作权限,查看用户信息下载用户数据
findPage接口是一个分页接口,会接收一个sortField字段,这个sortField最终会反映到SQL语句中,起到动态调整排序列的效果。
比如以下SQL语句:
1 | select * from user order by ${sortField} |
${sortField}会被替换为传入的值,比如age、name这些正常的值,还有一些非正常的值,比如1 and (SELECT 1271 from (select (sleep(10)))Ssvo),看下最后这个替换完会呈现什么效果
1 2 3 4 5 6 7 8 9 | SELECT * FROM test.user ORDER BY 1 AND (SELECT 1271 FROM (SELECT (SLEEP(10))) Ssvo) |
最终执行的效果就是睡眠10s,想象下如果有成百上千个sleep在数据库执行,我们的业务系统会怎样。
聪明的你也许会说为什么不用预编译解决这种SQL注入呢,在这种场景之下其实是不能使用预编译的,order by后面需要一个确切的列名,如果是问号,那SQL解析阶段就会报语法错误,那有什么办法可以解决呢?
1.控制sortField为一个有限的集合,不要直接替换到SQL中,增加一层判断
1 2 3 4 5 6 7 | if (sortField. equals ( "age" )){ sql.replace(${sortField}, "age" ); } else if (sortField. equals ( "name" )){ sql.replace(${sortField}, "name" ); } else { throw Exception( "不支持的排序列" ); } |
2.对sortField执行过滤,限制只能是数字、字母、下划线
1 | 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
安全问题无小事,以上两篇是我近期负责整改的一些安全漏洞的记录,希望能给大家带来些许帮助,后续如果还有这方面的内容会继续输出,我对安全领域也是小白一枚,以上内容如有纰漏,欢迎指正。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通