什么是SQL注入?
将前端的输入或传递的参数拼接成sql字符串语句的一部分,使得判断条件恒为正。
SELECT * FROM user_table WHERE username=
'’or 1 = 1 -- and password='’
如何预防SQL注入?
1.检测变量数据类型和格式
如果你的SQL语句是类似where id={$id}这种形式,数据库里所有的id都是数字,那么就应该在SQL被执行前,检查确保变量id是int类型,这样就不能传一些奇怪的值。
2.过滤特殊符号
对于无法确定固定格式的变量,一定要进行特殊符号过滤或转义处理。
3.绑定变量,使用预编译语句
MySQL的mysqli驱动提供了预编译语句的支持,不同的程序语言,都分别有使用预编译语句的方法。实际上,绑定变量使用预编译语句是预防SQL注入的最佳方式,使用预编译的SQL语句语义不会发生改变,在SQL语句中,变量用问号?表示,黑客即使本事再大,也无法改变SQL语句的结构。
什么是预编译语句?
sql语句经过执行分为词法解析、语法解析和语义解析最后优化执行计划后执行并返回结果,但很多时候有sql语句可能会反复执行,或者每次执行的时候只有个别的值不同。
如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。所谓预编译语句就是将这类语句中的值用占位符替代,可以视为将sql语句模板化或者说参数化,一般称这类语句叫Prepared Statements或者Parameterized Statements。
预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止sql注入。
MyBatis如何做到防止SQL注入的?
#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
$将传入的数据直接显示生成在sql中。
在MyBatis中,“${xxx}”这样格式的参数会直接参与SQL编译,从而不能避免注入攻击。但涉及到动态表名和列名时,只能使用“${xxx}”这样的参数格式。所以,这样的参数需要我们在代码中手工进行处理来防止注入。
MyBatis底层使用JDBC的PreparedStatement。PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。