Limitations of Java Prepared Statements in Certain Scenarios
Explains the difference between MyBatis parameter syntaxes, the limitations of prepared statements when handling variable table names and ORDER BY clauses, and the underlying mechanism by which precompilation prevents SQL injection.
Read in Chinese→0x00 The MyBatis Framework
The Difference Between # and `## 0x00 The MyBatis Framework
The Difference Between # and
#causes the statement to be precompiled${ }only performs string replacement; variables are substituted when the SQL is dynamically parsed
0x01 Limitations of Precompilation in Certain Scenarios
- When a table name is used as a variable, concatenation is required
select * from `user`
select * from 'user' #报错,表名不能使用单引号
- Concatenation is required after
order by
select * from user order by name
select * from user order by 'name' # 语义发生改变,没有排序的效果了
0x02 I Previously Heard Someone Say That Statements After order by Do Not Participate in Precompilation?
This statement is incorrect.
Order
bydoes participate in precompilation. As we can see from the JDBCsetStringalgorithm above,setStringadds quotation marks around the parameter, turning it into a string. This causesorder
byto lose its original meaning. It can only be said that usingorder
bywith precompilation is unsuitable. Therefore, to defend against this type oforder
byissue, it is recommended to hard-code it directly in the application. Fororder byinjection, we can retrieve data by observing differences in the order of the returned results.
0x03 Why Does Precompilation Ensure That Input Data Can Only Be Treated as Data, and What Is the Underlying Principle?
Generally speaking, an SQL statement goes through several stages between being submitted and executed: syntax tree generation, execution plan optimization, and execution. During precompilation, the database first receives an SQL statement containing the prepared-statement placeholder ?, parses it to generate a syntax tree (Lex), and caches it. It then receives the corresponding parameter information, retrieves the syntax tree from the cache, sets the parameters, and proceeds with optimization and execution. Because the syntax tree has already been generated before the parameter information is supplied, the syntactic structure being executed cannot be changed by the parameters, thereby naturally preventing SQL injection. This profound yet simple explanation should answer our initial question.