How to Prevent SQL Injection in MyBatis and Other ORM Frameworks
This article explains the principles behind SQL injection, common pitfalls in MyBatis and other ORM tools, and provides concrete safe coding patterns, configuration tips, and code examples to help developers eliminate injection vulnerabilities in their persistence layer.
This article explains common SQL coding defects, their underlying principles, causes, and mitigation strategies, with a focus on MyBatis and other ORM frameworks.
SQL Injection Vulnerability Principles and Causes
SQL injection occurs when external input is mistakenly treated as SQL code. The most effective solution is to use prepared statements. Executing an SQL statement involves three basic steps: code semantic analysis, execution‑plan generation, and obtaining the result set.
An SQL statement consists of code and data, for example:
SELECT id, name, phone FROM userTable WHERE name = 'xiaoming';In a prepared statement (MyBatis example) the SQL is analyzed with placeholders first:
SELECT id, name, phone FROM userTable WHERE name = #{name};During execution the data "xiaoming" is bound to the placeholder, preventing it from being parsed as code.
Historically developers used raw JDBC and concatenated user input directly into SQL, which easily creates injection holes. Modern projects are required to use ORM frameworks such as MyBatis.
Direct Use of MyBatis
Common Pitfalls
MyBatis supports two placeholder syntaxes: {} (string concatenation) and #{} (prepared‑statement placeholder). Using {} passes the parameter unchanged, leading to injection. For example:
SELECT id, name, phone FROM userTable WHERE name = '${name}';When name=xiaoming is supplied, the final SQL becomes
SELECT id, name, phone FROM userTable WHERE name = 'xiaoming';, which is vulnerable.
In ORDER BY clauses the column name must be injected with ${} because it is part of the SQL syntax, but this can cause errors if not validated.
Correct Practices
Use #{} for values and validate any ${} usage. For ORDER BY you can:
Apply conditional logic in the mapper XML to choose a safe column.
<select id="getUserAndOrder" resultType="Emp" parameterType="Emp">
select * from users where id < #{id}
<choose>
<when test="order == \"name\"">order by name</when>
<when test="order != \"age\"">order by age</when>
<otherwise>order by id</otherwise>
</choose>
</select>Additionally, filter the orderByClause with a whitelist (letters, digits, underscore) using a regular expression:
keyword = keyword.replaceAll("[^a-zA-Z0-9_\\s+]", "");Never rely on black‑list filtering.
MyBatis‑Generator Safe Usage
Dynamic Statement Support
MyBatis‑Generator can generate dynamic SQL modules. If developers concatenate raw input into ${criterion.condition}, injection occurs. The correct approach is to let the generator handle placeholders and bind values with #{}:
public void addKeywordTo(String keyword, UserExample example) {
example.or().andDisplayNameLike("%" + keyword + "%");
example.or().andOrgLike(keyword + "%");
example.or().andStatusLike("%" + keyword + "%");
example.or().andIdLike("%" + keyword + "%");
}Generated XML uses #{criterion.value} for data, keeping the code part separate.
Order By in Generated XML
The generator inserts order by ${orderByClause}. Without additional validation this is vulnerable, so the parameter must be filtered or the clause removed when not needed.
Other ORM Frameworks
Hibernate
Hibernate maps database tables to Java POJOs and uses HQL. Direct string concatenation in HQL creates injection risks:
List<Student> list = session.createQuery("FROM Student s WHERE s.stuId = " + stuId).list();Use placeholders or named parameters instead:
List<Student> list = session.createQuery("FROM Student s WHERE s.stuId = :stuId").setParameter("stuId", stuId).list();JPA
JPA follows the same principle. Unsafe concatenation leads to injection. Use prepared statements:
String sql = "SELECT username FROM users WHERE id = ?";
Query query = em.createNativeQuery(sql);
query.setParameter(1, id);
String username = (String) query.getSingleResult();Conclusion
Key takeaways:
There are many persistence‑layer components; each has its own security considerations.
Misunderstanding tool usage is the main cause of vulnerabilities.
Dynamic code generation in plugins makes simple pattern matching insufficient; comprehensive analysis of ORM behavior is required.
Reference links:
https://www.anquanke.com/post/id/190170#h2-3
https://www.cnblogs.com/alka1d/p/11582993.html
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Alibaba Cloud Developer
Alibaba's official tech channel, featuring all of its technology innovations.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
