MyBatis - iBATIS deja vu? Perhaps not…

by in Security

Our latest rulepack includes support for the MyBatis framework for Java, an object relational mapping (ORM) framework that’s an alternative to Hibernate. Including this framework in the rulepack came with some support difficulties that we had to overcome, due to the nature of static analysis.


We added support for iBATIS to our rulepacks back in 2007. However, in 2010 iBATIS 3.0 forked, leading to MyBatis. Initially, adding support for this ORM framework seemed like a potentially straightforward port of support, with just a new set of APIs that need to be supported.


This was not to be the case.


Similar to iBATIS, MyBatis allows developers to specify SQL queries within XML files that can then be picked up and referenced by their API. The tricky part of supporting MyBatis with a static analysis tool was their new “recommended” syntax. That new syntax doesn’t need to leverage MyBatis API calls directly at all. Instead, it maps the XML SQL queries to interface signatures that can be called directly as functions.


An example of this new syntax would be as such:


Within AccountMapper.xml:


<mapper namespace=“”>


<select id=“getUser”>


WHERE id=#{id}





Then, within (referenced in the mapper XML namespace attribute):




public interface AccountMapper{


public User getUser(int id);




MyBatis is a powerful framework and can understand beans, POJOs (Plain Old Java Objects), maps, and other complex objects, and then retrieve information from them via their public getters. In the example above, we see only that an integer is passed, but we don’t have to specify the type that is passed to the query; the type is implicitly determined by the MyBatis framework. In the old style of calling SQL queries (still available within MyBatis), this would be called with a line of code such as:


User user = session.selectOne(“”, userId);


The line above is straightforward to support by even the most basic static analysis tool, since we are seeing a specific MyBatis API call that’s calling a query. It’s relatively easy to determine that potentially user-controlled data could be used to query the database via the userId parameter, and that the information from the database would be returned to user.


With the new MyBatis syntax, however, you can call this function by doing:


mapper = session.getMapper(“”);

User user = mapper.getUser(userId);


Again, this wouldn’t be particularly difficult to deal with, since we can see the direct call to the MyBatis framework with getMapper(). We can recognize that any function on mapper will be a query against the database where the parameters could be potentially user-controlled. Anything that’s returned from these functions is potentially information from the database (at least for SELECT queries). It’s not pretty, and it could potentially lead to false positives if an UPDATE SQL query is run, which will just return the value of the number of records updated and can be seen as fairly benign data.


The biggest problem when trying to model this scenario with a static analysis tool is that along with MyBatis, there is a plug-in for the Spring framework, MyBatis-Spring. This includes other functionality such as SqlSessionFactoryBean, which could be implemented as:


<bean id=”sqlSessionFactoryBean” class=”org.mybatis.spring.SqlSessionFactoryBean”>

<property name=”dataSource” ref=”dataSource”/>

<property name=”mapperLocations” value=”classpath*:sample/config/mappers/**/*.xml”/>



The above shows within the value for mapperLocations that the plug-in has the ability to search recursively through directories to identify mapper files using common ant-like syntax. Although this makes applications easier to implement, it makes it much harder for a static analysis tool to identify the mapper classes. Therefore it inherently makes it much more difficult to determine the functions within that class that could potentially send user-controlled data into SQL queries and return data from the database.


Using Spring’s resource injection functionality, any tool that scans the code (such as a static analysis tool) won’t necessarily ever see a direct call to the MyBatis framework. An example of this is shown within the MyBatis-Spring sample code available online, which does not contain a single call to the MyBatis API.


Identifying mapper classes


All of this brings three challenges to static analysis, one of which we’ve already come across:

1) How do we identify what is a mapper class?

2) How do we identify the correct functions within this mapper class that could potentially return data from the database?

3) How do we identify functions potentially vulnerable to SQL injection or tampering of the parameters?


These are all tough challenges for a static analysis tool scanning the source code, since all the functionality could be occurring in the background and not in the code. By reading the XML Mapper files and annotations associated with the query functions, we managed to map these to the interface API calls to discover the correct functions that query the database. We could then use this information to differentiate between the different types of SQL queries to determine whether information returned is from the database (SELECT queries) or benign (UPDATE, DELETE and INSERT queries).


SQL injection, access control vulnerabilities, or both?


There are two types of vulnerabilities we commonly find with SQL queries that take user-controlled data: SQL injections and access control vulnerabilities. While SQL injections are commonly understood by most developers by now, many know little about access control vulnerabilities.


With access control vulnerabilities, we’re not worried about being able to inject values into SQL queries in order to change the meaning of the query. Instead, this vulnerability is more of a logic flaw, being able to use an ordinary value to break business logic and to potentially enumerate all records in a database. However, determining whether the issue is valid usually requires auditing, since it may be by design. For example, an e-commerce site with a URL containing an id parameter indicating the product primary key in the database may be that way by design, as the site may want customers to see all their available products.


Thankfully, being able to determine if a query is vulnerable to one or both of these problems is fairly straightforward with MyBatis, provided you can check the SQL query performed in the XML mapper file (or functions annotations). SQL queries within MyBatis mapper files should only be susceptible to SQL injection and access control issues via the use of variables inside ${…}. If developers are using parameterized queries inside #{…}, they shouldn’t be vulnerable to SQL injection, but the query and program logic will determine if they are still vulnerable to access control issues or not.


In terms of programming an application with the use of MyBatis, however, you should very rarely need to use SQL injection-susceptible parameters with ${…}, as MyBatis contains a very comprehensive XML schema that allows for dynamic SQL query generation.


If you do come across possible SQL injection issues within your code, consider whether these can be worked around using parameterized queries and the XML constructs that the MyBatis framework has provided. Further information can be found at the links below:


MyBatis: Dynamic SQL

MyBatis-Spring: Getting Started

MyBatis Blog


Static Analyzer