资讯专栏INFORMATION COLUMN

一次mybatis中ognl引发的bug排查

RichardXG / 2383人阅读

摘要:现象项目组一妹子程序员求助,说有,有一个值明明设置的是,但是存到数据库里面却会自动变成,尝试了各种调整也找不原因,都快急疯了我以前确实没有研究过源码,本着专研问题的精神,决定通过对一探究竟。

现象

  项目组一妹子程序员求助,说mybatis有bug,有一个值明明设置的是A.prop1=XXX,但是存到数据库里面却会自动变成A.prop1=true,尝试了各种调整也找不原因,都快急疯了!我以前确实没有研究过mybatis源码,本着专(ba)研(mei)问(zhuang)题(b)的精神,决定通过debug对mybais一探究竟。

定位

  debugDao的入口类便是org.apache.ibatis.binding.MapperProxy ,可以看到它实现了InvocationHandler,很明显mybatis使用了jdk的动态代理,参见查看我以前关于动态代理类的培训ppt如下,那么它一定有地方使用了newProxyInstance生成代理类,果然在MapperProxyFactory中就可以找到对应的方法,只不过这次动态代理是对纯接口进行代理,而不是对实现类代理(当然满足动态代理中被代理类需要实现接口的要求了!)

  进入到MapperMethod中的execute方法,可以看到mybatis对select、update、delete、insert有不同的分支处理:

  进入到出问题的update方法中,可以定位到sqlSession.update执行时修改了传入的参数值,把XXX改成了true,这个update方法到底藏了什么玄机?继续进入,发现sqlSession也是spring sessionTemplate生成的一个动态代理,主要是增加获取链接和事物操作,通过代理层的操作,进入Mybatis的DefaultSqlSession中,接下来就是Mybatis预编译要动态生成sql语句了,在动态生成语句时终于最终定位到了罪魁祸首ifSqlNode.apply方法(整体调用栈见下图)!

解决

  mybatis中会根据mapper文件生成一个SqlNodeTree,然后根据入参的数据有选择的生成最终的SQL,例如mapper文件中支持语法,if test的条件动态决定update或者where的sql语句是否存在,例如传过来的A对象中没有prop1属性,那么if test A.prop1!=null判断一下,如果没有的话,最终的sql就不包含update prop1=?,达到灵活和提高性能的目的。这个ifSqlNode就是mapper if test语法的具体Node,但是这个node应该只是判断是否存在这个条件啊!怎么会改值的?
  进入到具体的判断方法内部,发现了原来这边判断if test是使用的Ognl表达式引擎啊,Ognl是一个功能非常强大的JAVA表达式引擎,但是由于过于强大了,导致使用它的Struts2漏洞漫天飞,你Http请求中传参"Runtime.getRuntime.exec("shutdown")",它真的就给你执行关机了你敢信!!。

/*    */   public boolean evaluateBoolean(String expression, Object parameterObject)
/*    */   {
/* 29 */     Object value = OgnlCache.getValue(expression, parameterObject);
/* 30 */     if (value instanceof Boolean) return ((Boolean)value).booleanValue();
/* 31 */     if (value instanceof Number) return (!(new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO)));
/* 32 */     return (value != null);
/*    */   }

  敏锐的我对着expression看了一遍又一遍,突然,我眼花了么?

A.prop1=!null !
A.prop1=!null !!
A.prop1=!null !!!

  你妹啊! "!="写成了"=!"!ognl又一次立功了,在需要它判断的时候,它忠实的执行了赋值(怪OGNL不怪妹子是几个意思?),修改了mapper文件中的错误,终于恢复了正常!

扩展

  上网搜索下看看有没有犯同样错误的同学,没想到还真有人在mybatis中这样玩OGNL的,根据if test判断的结果给table名赋值,无疑是提供了一种崭(hun)新(luan)的思路!!
  给你们这些挖坑的跪了!


            select from ${dynamicTableName }

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/77210.html

相关文章

  • MyBatis支持OGNL语法

    摘要:支持的语法用于解析静态方法解析表达式在映射语句中可以支持引入以下几种方式示例变量属性静态方法无参数待参数静态属性数组索引集合构造方法的静态方法可以省略的编写,方法的默认是包下的静态方法可以省略的编写,类默认的是语法中通过两个字符,前者 Mybatis支持OGNL的语法 OgnlCache 用于解析静态方法org.apache.ibatis.scripting.xmltags.TextS...

    wh469012917 评论0 收藏0
  • Mybatis常见面试题

    摘要:执行没有,批处理不支持,将所有都添加到批处理中,等待统一执行,它缓存了多个对象,每个对象都是完毕后,等待逐一执行批处理。 Mybatis常见面试题 #{}和${}的区别是什么? #{}和${}的区别是什么? 在Mybatis中,有两种占位符 #{}解析传递进来的参数数据 ${}对传递进来的参数原样拼接在SQL中 #{}是预编译处理,${}是字符串替换。 使用#{}可以有效的防止...

    liuchengxu 评论0 收藏0
  • 一次排查多线程引发Java DNS缓存Bug

    摘要:问题描述最近通知应用在近三个月内出现过次缓存的问题,第一次在重启之后一直没有出现过问题,所以也没有去重视,但是最近又出现过一次,看来很有必要彻底排查一次具体的错误日志如下具体表现就是出现此异常之后连续的出现大量此异常 问题描述最近通知应用在近三个月内出现过2次DNS缓存的问题,第一次在重启之后一直没有出现过问题,所以也没有去重视,但是最近又出现过一次,看来很有必要彻底排查一次;具体的错...

    cocopeak 评论0 收藏0
  • 笔记|软件调试技巧

    摘要:在软件世界里,观察意味着设置断点添加调试语句监视程序值以及检查内存在医学领域,需要测试血样和进行光透视。福尔摩斯,最后一案如果你不修复,它不会自动消失。修复解决问题的能力,是软件工程师的核心竞争力之一。 这篇文章是《调试九法:软硬件错误的排查之道》的阅读笔记。这本书的主旨,是介绍如何修复bug:找出bug发生的原因、并给出修复方案。 调试bug的九个规则列举如下,建议将这个清单打印出来...

    DirtyMind 评论0 收藏0
  • Mybatis源码分析(1) - Mybatis包目录简介

    摘要:核心包包名称包内内容简介注解目录。如等类的实例反射生成工具目录主要是注解,和的构造器及转换器内部缓存接口。等默认的游标处理类数据源工厂类及实现。数据源实现类自定义的三个异常类。。都继承自执行器相关包。为后续分析源码打下基础。 Mybatis核心包 showImg(https://segmentfault.com/img/remote/1460000018747383?w=746&h=1...

    chengtao1633 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<