SQL注射原理

SQL注射能使***者绕过认证机制,完全控制远程服务器上的数据库。SQL是结构化查询语言的简称,它是访问数据库的事实标准。目前,大多数Web应用都使用SQL数据库来存放应用程序的数据。几乎所有的Web应用在后台都使用某种SQL数据库。跟大多数语言一样,SQL语法允许数据库命令和用户数据混杂在一起的。如果开发人员不细心的话,用户数据就有可能被解释成命令,这样的话,远程用户就不仅能向Web应用输入数据,而且还可以在数据库上执行任意命令了。
登陆验证
现在以一个需要用户身份认证的简单的Web应用程序为例进行讲解。假定这个应用程序提供一个登录页面,要求用户输入用户名和口令。用户通过HTTP请求发送他们的用户名和口令,之后,Web应用程序检查用户传递来用户名和口令跟数据库中的用户名和口令是否匹配。这种情况下,会要求在SQL数据库中使用一个数据库表。
对一个用户进行认证,实际上就是将用户的输入即用户名和口令跟表中的各行进行比较,如果跟某行中的用户名和口令跟用户的输入完全匹配,那么该用户就会通过认证。
假如后台的sql语句时这样拼接的

select id
from test
where username=
‘”+myname+”‘
and password=
‘”+mypasswd+”‘“;

表面上看,如果用户名和口令对匹配,那么该用户通过认证;否则,该用户不会通过认证——但是,事实果真如此吗?非也!读者也许已经注意到了,这里并没有对SQL命令进行设防,所以
***者完全能够在用户名或者口令字段中注入SQL语句,从而改变SQL查询。为此,我们仔细研究一下上面的SQL查询字符串:

上述代码认为字符串username和password都是数据,不过,***者却可以随心所欲地输入任何字符。如果一位***者输入的用户名为
’OR1=1—
而口令为
x
双划符号–告诉SQL解析器,右边的东西全部是注释,所以不必理会。这样,查询字符串相当于:
select
id from test where username= or 1=1;

如今的SELECT语句跟以前的已经大相径庭了,因为现在只要用户名为长度为零的字符串”或1=1这两个条件中一个为真,就返回用户标识符ID——我们知道,1=1是恒为真的。所以这个语句将返回user_table中的所有ID。在此种情况下,***者在username字段放入的是SQL指令’OR1=1–而非数据。
更为严重的情况是当username对应的是’OR1=1;DROPTABLEuser_table;–
数据库中执行的sql语句就变成了:

select id
from test
where username=

or 1=1;
drop
table test

这个语句将执行句法上完全正确的SELECT语句,并利用drop命令清空test表。

应对策略
问题的关键就是不要用string构造sql语句,这样就不会利用输入的参数构造sql语句了。所以要用PreparedStatement替换Statement,即用占位符作为实参定义sql语句,从而避免sql注入***。
不管什么框架,还是纯JDBC,只用Preparedstatement,一定要用占位符作为实参来构造sql(或hql)语句。

String sql=
“select * from test where usernmae=? and password=?;


PreparedStatement psm=conn.preparedStatement(sql);
psm.setString(1,myname);
psm.setString(2,mypasswd);
Result rs=psm.executeQuery();



if(rs.next){

rs.close();

con.close();


return
false;

}


else{

rs.close();

con.close();


return
true;

}