SQL注入原理及PreparedStatement的使用

SQL注射原理

SQL 注射能使攻击者绕过认证机制,完全控制远程服务器上的数据库。SQL是结构化查询语言的简称,它是访问数据库的事实标准。目前,大多数Web应用都使用 SQL数据库来存放应用程序的数据。几乎所有的Web应用在后台都使用某种SQL数据库。跟大多数语言一样,SQL语法允许数据库命令和用户数据混杂在一 起的。如果开发人员不细心的话,用户数据就有可能被解释成命令,这样的话,远程用户就不仅能向Web应用输入数据,而且还可以在数据库上执行任意命令了。

1.登陆验证

现 在以一个需要用户身份认证的简单的Web应用程序为例进行讲解。假定这个应用程序提供一个登录页面,要求用户输入用户名和口令。用户通过HTTP请求发送 他们的用户名和口令,之后,Web应用程序检查用户传递来用户名和口令跟数据库中的用户名和口令是否匹配。这种情况下,会要求在SQL数据库中使用一个数 据库表。

对一个用户进行认证,实际上就是将用户的输入即用户名和口令跟表中的各行进行比较,如果跟某行中的用户名和口令跟用户的输入完全匹配,那么该用户就会通过认证。

假如后台的sql语句时这样拼接的

select id from test where username='"+myname+"' and password='"+mypasswd+"' ";

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

扫描二维码关注公众号,回复: 600450 查看本文章

上述代码认为字符串username和password都是数据,不过,攻击者却可以随心所欲地输入任何字符 。如果一位攻击者输入的用户名为

’OR 1=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注入攻击(使用PreparedStatement时 会先将sql 语句预处理一下并存放于内存中,占位符区域 只会当成参数,不会成为sql的一部分。而使用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 ;
}

猜你喜欢

转载自weigang-gao.iteye.com/blog/2110591