1. 什么是SQL注入?
SQL注入是常见的网络攻击方式之一,通过SQL语句实现无账号登录,非法获取甚至篡改数据库中的数据。
2. SQL注入的思路
(1)找到SQL注入位置;
(2)判断服务器类型和后台数据库类型;
(3)针对不同的服务器和数据库进行SQL注入攻击;
3. SQL注入的实例——'or 1=1 --始终为真
(1)匿名登录
用户名 | SQL injection |
密码 | |
验证码 | 'or 1=1-- |
这是一个很常见的登录界面,如果系统对用户的输入没有数据约束来阻止错误输入,那么用户可以故意的输入一些错误输入。当用户输入以上数据时,对应的SQL语句如下:
SELECT * From Users WHERE UserId='SQL inject' and Password='' and Seccode='' or 1=1--'
可以看到Seccode这一字段的前半个单引号被闭合了,后半个单引号被“--”注释掉了。无论前面的UserId和Password输入正确与否,总有“1=1”成立,所以可以轻松骗过系统,实现匿名登录。
(2)获取数据库和服务器操作系统信息
用户名 | SQL injection |
密码 | |
验证码 | 'or 1=(SELECT @@VERSION)-- |
现在判定条件变成了 1=(SELECT @@VERSION),这种写法肯定会导致错误,但就是要利用这种错误来获取我们想要的信息。点击登录之后,页面返回以下信息:
Conversion failed when converting the nvarchar value 'Microsoft SQL Server 2008 (SP3) - 10.0.5500.0 (X64) Sep 21 2011 22:45:45
Copyright (c) 1988-2008 Microsoft Corporation Developer Edition (64-bit) on Windows NT 6.1 <X64> (Build 7601: Service Pack 1) ' to data type int.
可以看到服务器的操作系统信息和数据库的版本信息通过错误显示出来。
4. 预防SQL注入
(1)使用java PreparedStatement
之所以PreparedStatement能防止注入,是因为它把单引号转义了,变成了\',这样一来,就无法截断SQL语句,进而无法拼接SQL语句,基本上没有办法注入了。
String sql = "select * from Users where min_name = ?"; // 含有参数
PreparedStatement st = conn.prepareStatement(sql);
st.setString(1, "'or1=1--"); // 参数赋值
System.out.println(st.toString()); //com.mysql.jdbc.JDBC4PreparedStatement@d704f0:select * from goods where min_name = '\'or1=1'
(2)使用正则表达式过滤传入的参数;
(3)对用户输入的数据类型做严格限制;
(4)在应用发布之前建议使用专业的SQL注入检测工具进行检测,以及时修补被发现的SQL注入漏洞。网上有很多这方面的开源工具,例如sqlmap、SQLninja等。
(5)避免网站打印出SQL错误信息,比如类型错误、字段不匹配等,把代码里的SQL语句暴露出来,以防止攻击者利用这些错误信息进行SQL注入。
总结:
关于安全性,本文可总结出一下几点:
- 对用户输入的内容要时刻保持警惕。
- 只有客户端的验证等于没有验证。
- 永远不要把服务器错误信息暴露给用户。
除此之外,我还要补充几点:
- SQL注入不仅能通过输入框,还能通过Url达到目的。
- 除了服务器错误页面,还有其他办法获取到数据库信息。
- 可通过软件模拟注入行为,这种方式盗取信息的速度要比你想象中快的多。
- 漏洞跟语言平台无关,并非asp才有注入漏洞而asp.net就没有注入漏洞,一切要看设计者是否用心。
参考:https://www.cnblogs.com/hkncd/archive/2012/03/31/2426274.html