朗沃教育 朗沃L君
SQL注入攻击,是黑客对数据库进行攻击的常用手段之一。那么,什么是SQL注入?SQL注入是怎么发生的?如何防止SQL注入?我们今天就来了解一下。
SQL注入产生的背景
在企业级应用中,存储数据主要是使用数据库来实现。数据库有着强大的数据存储能力和数据处理性能。
对于开发者而言,完成数据库的数据存储和数据处理,主要是利用SQL语句来实现的。不过,SQL语句中的数据是由用户在客户端通过文本框进行数据录入,然后,通过表单提交的方式请求服务器。开发者为了将客户端提交的数据和数据库进行数据的交互。就需要将客户端提交的数据和SQL语句的进行拼接,形成一条完整的能够执行的SQL语句。然后,交给DBMS执行,完成数据的存储以及数据处理。
举个添加的例子,SQL语句应该书写如下:
insert into t_user(userName,sex) values('tom','男');
这条SQL语句执行完成后,可以向数据库添加用户名为”tom”,性别为”男”的记录。但是,在实际应用中,用户名和性别应该是由客户端提供的。这时,开发者应该先得到从客户端提交数据,然后拼接成添加SQL语句,交由DBMS执行。
String name = request.getParameter("userName");
String sex = request.getParameter("sex");
String sql="insert into t_user(userName,sex)values('"+name+"','"+sex+"')";
这时,如果客户端提交的userName值为”john”,性别为”男”。那么拼接后的SQL语句就应该是:
String sql = "insert into t_user(userName,sex) values('john','男')";
这样,DBMS在执行SQL语句后,就会将”john”和”男”添加进数据库。
不过,在这个过程中,存在一些漏洞可以被黑客所攻击。如果客户端提交的数据存在一些非法字符或数据库关键字时,可能会造成SQL语句发生错误,或执行结果不正确的情况。
在上面的示例中,如果客户端提交的userName值为”jo’hn”。性别为”男”。那么拼接后的SQL语句就应该是:
String sql = "insert into t_user(userName,sex) values('jo'hn','男')";
很明显,这条SQL语句不满足添加语句的语法。DBMS在执行时会报SQL语句语法错误。
再来看一个登陆的例子,sql语句应该书写如下:
String name = request.getParameter("userName");
String password = request.getParameter("password");
String sql = "select * from t_user where userName='" + name +
"' and password='"+password+"'";
这条SQL语句的本意是,查询用户名和密码同时相等的记录。如果客户端提交的userName值为”tom”,密码为”123”。那么拼接后的SQL语句就应该是:
String sql = "select * from t_user where userName='tom' and "
+ "password='123'";
但是,如果客户端提交的userName值为”aaa”。密码为”bbb’ or ‘1’=’1”。那么拼接后的SQL语句就应该是:
String sql = "select * from t_user where userName='aaa' and "
+ "password='bbb' or '1'='1'";
由于’1’=’1’固定为true,所以,这条SQL语句的查询结果,是t_user表中所有记录。这样的话,无论用户名和密码输什么值,都可以有结果返回。从而,开发者会得到”登陆成功”的错误结论。
有些黑客也利用,在数据中加入”--“的方式,注释掉SQL语句中的条件。比如,客户端提交的userName值为”aaa’ or 1=1 -- “。密码为”bbb”。那么拼接后的SQL语句就应该是:
String sql = "select * from t_user where userName='aaa' or 1=1 -- '"
+ " and password='bbb'";
这样,1=1固定为true,而以后的SQL语句会因为注释不会执行。
如果黑客再坏一点,在数据中加入DDL操作,比如:在密码中填入”bbb’;drop table t_user;”,那么SQL语句就变成:
String sql = "select * from t_user where userName='aaa' and "
+ "password='bbb';drop table t_user";
执行SQL语句后,表都没了。
什么是SQL注入?
所谓SQL注入,是将客户机提交或Web表单递交的数据,拼接成SQL语句字符串时。如果客户端提交的数据有非法字符或SQL语句关键字时,会造成执行的SQL语句语法错误,或执行结果不正确的情况。通过SQL注入,黑客可以最终达到欺骗服务器,执行恶意的SQL语句,甚至破坏数据库结构的目的。
SQL注入攻击大多是利用设计上的漏洞,在目标服务器上运行Sql语句的攻击方式。开发者在动态生成Sql语句时,没有对用户输入的数据进行验证,是Sql注入攻击得逞的主要原因。
如何防止SQL注入?
在java中,是使用JDBC和数据库建立连接,并执行SQL语句,和数据库进行数据交互的。
JDBC在执行SQL语句操作时,提供了Statement、PreparedStatement和CallableStatement三种方式来执行SQL语句。其中 Statement 用于通用查询, PreparedStatement 用于执行参数化查询,而 CallableStatement则是用于存储过程。
在三个接口中,Statement是PreparedStatement和CallableStatement的父接口。Statement在执行SQL语句时,对于客户端提交的数据只支持拼接SQL语句的方式。
所以,使用Statement在执行SQL语句,容易引起SQL注入。PreparedStatement在执行参数化查询时,支持占位符方式。
在使用参数化查询的情况下,数据库系统不会将参数的内容,视为SQL指令的一部分来处理。而是在数据库完成SQL指令的编译后,才套用参数运行。因此,就算参数中含有破坏性的指令,也不会被数据库所运行。所以,使用PreparedStatement的参数化查询可以有效的阻止SQL注入。
另外,PreparedStatement相比Statement还有以下几个优势
1、可以预编译SQL语句,多次查询时速度快。
2、防止数据库缓冲区溢出
3、代码的可读性可维护性好
由于有以上优点,所以,在开发JDBC时,PreparedStatement成为访问数据库的语句对象的首选。
总结:
所谓SQL注入,是将客户机提交或Web表单递交的数据,拼接成SQL语句字符串时。如果客户端提交的数据有非法字符或SQL语句关键字时,会造成执行的SQL语句语法错误,或执行结果不正确的情况。通过SQL注入,黑客可以最终达到欺骗服务器,执行恶意的SQL语句,甚至破坏数据库结构的目的。
在JDBC中使用PreparedStatement的参数化查询,数据库系统不会将参数的内容,视为SQL指令的一部分来处理。可以有效防止SQL注入。
开发JDBC时,尽量采用 PreparedStatement执行SQL语句,相比Statement有以下优势:
a、可以防止SQL注入
b、可以预编译SQL语句,多次查询时速度快
c、防止数据库缓冲区溢出
d、代码的可读性可维护性好
领取专属 10元无门槛券
私享最新 技术干货