MyBatis prevents SQL injection

    SQL injection is a code injection technique used to attack data-driven applications, where malicious SQL statements are inserted into executed entity fields (for example, to dump database contents to an attacker ). [Excerpt from]  SQL injection - Wikipedia

SQL injection , everyone is familiar with, is a common attack method. An attacker can enter some strange SQL fragments (such as "or '1'='1'") on the form information or URL of the interface, and it is possible to invade the application with insufficient parameter validation . Therefore, we need to do some work in our application to prevent such attacks. In some applications with high security requirements (such as banking software), it is often used to replace all SQL statements with stored procedures to prevent SQL injection. This is of course a very safe way , but in our usual development, we may not need this rigid way.

As a semi-automatic persistence layer framework, the MyBatis framework requires us to manually write its SQL statements. Of course, we need to prevent SQL injection at this time . In fact, MyBatis's SQL is a function with " input + output ", similar to the structure of a function, as follows:

 

<select id="getBlogById" resultType="Blog" parameterType=”int”>

         SELECT id,title,author,content

         FROM blog

WHERE id=#{id}

</select>

 

Here, parameterType represents the input parameter type, and resultType represents the output parameter type. In response to the above, if we want to prevent SQL injection, of course we have to work on input parameters. The yellow highlight in the above code is the part where the input parameters are spliced ​​in the SQL. After passing in the parameters, print out the executed SQL statement, and you will see that the SQL is like this:

SELECT id,title,author,content FROM blog WHERE id = ?

No matter what parameters are entered, the printed SQL is like this. This is because MyBatis enables the pre-compilation function. Before the SQL is executed, the above SQL will be sent to the database for compilation; when executing, the compiled SQL can be used directly, and the placeholder "?" can be replaced. Because SQL injection can only work on the compilation process, this way can well avoid the problem of SQL injection.

[Low-level implementation principle] How does MyBatis achieve SQL pre-compilation? In fact, at the bottom of the framework, the PreparedStatement class in JDBC is at work. PreparedStatement is a subclass of Statement that we are familiar with. Its object contains compiled SQL statements. This "prepared" approach not only improves security, but also improves efficiency when executing the same SQL multiple times. The reason is that the SQL is already compiled and does not need to be compiled again when executing it again.

Having said that, can we prevent SQL injection by using MyBatis? Of course not, see the code below:

<select id="getBlogById" resultType="Blog" parameterType=”int”>

         SELECT id,title,author,content

         FROM blog

WHERE id=${id}

</select>

仔细观察,内联参数的格式由“#{xxx}”变为了“${xxx}”。如果我们给参数“id”赋值为“3”,将SQL打印出来是这样的:

SELECT id,title,author,content FROM blog WHERE id = 3

(上面的对比示例是我自己添加的,为了与前面的示例形成鲜明的对比。)

<select id="orderBlog" resultType="Blog" parameterType=”map”>

         SELECT id,title,author,content

         FROM blog

ORDER BY ${orderParam}

</select>

仔细观察,内联参数的格式由“#{xxx}”变为了“${xxx}”。如果我们给参数“orderParam”赋值为“id”,将SQL打印出来是这样的:

SELECT id,title,author,content FROM blog ORDER BY id

显然,这样是无法阻止SQL注入的。在MyBatis中,“${xxx}”这样格式的参数会直接参与SQL编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用“${xxx}”这样的参数格式。所以,这样的参数需要我们在代码中手工进行处理来防止注入。

【结论】在编写MyBatis的映射语句时,尽量采用“#{xxx}”这样的格式。若不得不使用“${xxx}”这样的参数,要手工地做好过滤工作,来防止SQL注入攻击。

 

#{}:相当于JDBC中的PreparedStatement

${}:是输出变量的值

简单说,#{}是经过预编译的,是安全的${}是未经过预编译的,仅仅是取变量的值,是非安全的,存在SQL注入。

如果我们order by语句后用了${},那么不做任何处理的时候是存在SQL注入危险的。你说怎么防止,那我只能悲惨的告诉你,你得手动处理过滤一下输入的内容。如判断一下输入的参数的长度是否正常(注入语句一般很长),更精确的过滤则可以查询一下输入的参数是否在预期的参数集合中

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326175658&siteId=291194637