一、先来了解什么是SQL注入??
所谓SQL注入,就是通过把SQL命令插入到Web表单提交或页面请求url的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。具体来说,它是利用现有应用程序,将(恶意)的SQL命令注入到后台数据库引擎执行的能力,它可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者意图去执行SQL语句。
不好理解,来看实例。
2、 实战举例
有个登陆框如下:
可以看到除了账号密码之外,还有一个公司名的输入框,根据输入框的形式不难推出SQL的写法如下:
SELECT * From table_name WHERE name='XX' and password='YY' and corporate='ZZ'
怎么做呢,?
因为没有校验,因此,我们账号密码,都不填写,直接在最后,添加 or 1=1 --
看看与上面SQL组合,成了如下:
SELECT * From table_name WHERE name='' and password='' and corporate='' or 1=1-'
从代码可以看出,前一半单引号被闭合,后一半单引号被 "--"给注释掉,中间多了一个永远成立的条件"1=1",这就造成任何字符都能成功登录的结果。
3、 提醒
不要以为在输入框做个检查就够了,不要忘记了,我们web提交表单,是可以模拟url直接访问过去,绕开前段检查。因此,必须是后端,或是数据来检查才能有效防止。
(1) 检查用户输入的合法性;
(2) 将用户的登录名、密码等数据加密保存。
(3) 预处理SQL。
(4) 使用存储过程实现查询,虽然不推荐,但也是一个方法。
4、 MySQL预处理是怎么防止的呢?
其实是因为SQL语句在程序运行前已经进行了预编译,在程序运行时第一次操作数据库之前,SQL语句已经被数据库分析,编译和优化,对应的执行计划也会缓存下来并允许数据库已参数化的形式进行查询,当运行时动态地把参数传给PreprareStatement时,即使参数里有敏感字符如 or '1=1'也数据库会作为一个参数一个字段的属性值来处理而不会作为一个SQL指令,如此,就起到了SQL注入的作用了!
具体像这样。例如刚刚那条SQL:
SELECT * From table_name WHERE name='' and password='' and corporate='' or 1=1-'
开启预编译执行SQL的时候,则不会这么处理。会当成一个属性值。什么意思。随便你怎么加,都是一个值。也就是说,如果中间有产生歧义的,都将被处理掉,最后执行相当于是这样:
5、
SELECT * From table_name WHERE name='' and password='' and corporate="'or 1=1--"
6、 MySQL开启预编译
通过 PREPARE stmt_name FROM preparable_stm的语法来预编译一条sql语句,
mysql> prepare i_statms from 'insert into t select ?,?';
Query OK, 0 rows affected (0.00 sec)
Statement prepared
我们通过EXECUTE stmt_name [USING @var_name [, @var_name] ...]的语法来执行预编译语句:
mysql> set @a=999,@b='hello';
Query OK, 0 rows affected (0.00 sec)
mysql> execute i_statms using @a,@b;
Query OK, 1 row affected (0.01 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from t;
+------+-------+
| a | b |
+------+-------+
| 999 | hello |
+------+-------+
1 row in set (0.00 sec)
可以看到,数据已经被成功插入表中。
MySQL中的预编译语句作用域是session级,但我们可以通过max_prepared_stmt_count变量来控制全局最大的存储的预编译语句。
手动释放:
如果我们想要释放一条预编译语句,则可以使用{DEALLOCATE | DROP} PREPARE stmt_name的语法进行操作:
mysql> deallocate prepare i_statms;
Query OK, 0 rows affected (0.00 sec)
7、 java Connector/J 如何开启
MySQL Java驱动Connector/J(版本5.1.42)为例来介绍通过MySQL驱动进行预编译。
目前该最新稳定版为5.1.45。
JDBC中
java.sql.PreparedStatement是java.sql.Statement的子接口,它主要提供了无参数执行方法如executeQuery和executeUpdate等,以及大量形如set{Type}(int, {Type})形式的方法用于设置参数。
这里有几个重要的参数需要注意:
useServerPrepStmts=true开启MySQL预编译,默认FALSE。
cachePrepStmts=true开启预编译缓存,默认FALSE。
prepStmtCacheSize 控制缓存的条数,默认25,建议配置260-500之间。
prepStmtCacheSqlLimit 控制长度多大的sql可以被缓存,默认256,建议配置1024。
你学会了吗?点赞+关注,更多专业内容。