|
一、什么是sql注入?
1、什么是sql注入呢?
所谓SQL注入,就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,
最终达到欺骗服务器执行恶意的SQL命令,比如先前的很多影视网站泄露VIP会员密码大多就是通过
WEB表单递交查询字符暴出的,这类表单特别容易受到SQL注入式攻击.当应用程序使用输入内容
来构造动态sql语句以访问数据库时,会发生sql注入攻击。如果代码使用存储过程,而这些存储过程
作为包含未筛选的用户输入的字符串来传递,也会发生sql注入。 黑客通过SQL注入攻击可以拿到网
站数据库的访问权限,之后他们就可以拿到网站数据库中所有的数据,恶意的黑客可以通过SQL注
入功能篡改数据库中的数据甚至会把数据库中的数据毁坏掉。做为网络开发者的你对这种黑客行
为恨之入骨,当然也有必要了解一下SQL注入这种功能方式的原理并学会如何通过代码来保护自己
的网站数据库
2、sql注入产生原因
sql注入攻击是利用是指利用设计上的漏洞,在目标服务器上运行Sql语句以及进行其他方式的攻
击,动态生成Sql语句时没有对用户输入的数据进行验证是Sql注入攻击得逞的主要原因。对于java
数据库连接JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement是无效的,这是
因为PreparedStatement不允许在不同的插入时间改变查询的逻辑结构。
如验证用户是否存在的SQL语句为:
用户名'and pswd='密码
如果在用户名字段中输入: 'or 1=1或是在密码字段中输入:'or 1=1
将绕过验证,但这种手段只对只对Statement有效,对PreparedStatement无效。相对Statement有
以下优点:
1.防注入攻击
2.多次运行速度快
3.防止数据库缓冲区溢出
4.代码的可读性可维护性好
这四点使得PreparedStatement成为访问数据库的语句对象的首选,缺点是灵活性不够好,有些场
合还是必须使用Statement。
3、sql注入原理
下面我们来说一下sql注入原理,以使读者对sql注入攻击有一个感性的认识,至于其他攻击,原
理是一致的。
SQL注射能使攻击者绕过认证机制,完全控制远程服务器上的数据库。 SQL是结构化查询语言的
简称,它是访问数据库的事实标准。目前,大多数Web应用都使用SQL数据库来存放应用程序的数
据。几乎所有的Web应用在后台 都使用某种SQL数据库。跟大多数语言一样,SQL语法允许数据库
命令和用户数据混杂在一起的。如果开发人员不细心的话,用户数据就有可能被解释成命令, 这样
的话,远程用户就不仅能向Web应用输入数据,而且还可以在数据库上执行任意命令了。
SQL注入式攻击的主要形式有两种。一是直接将代码插入到与SQL命令串联在一起并使得其以执
行的用户输入变量。上面笔者举的例子就是采用了这种方法。由于其直接与SQL语句捆绑,故也被
称为直接注入式攻击法。二是一种间接的攻击方法,它将恶意代码注入要在表中存储或者作为原书
据存储的字符串。在存储的字符串中会连接到一个动态的SQL命令中,以执行一些恶意的SQL代码。
注入过程的工作方式是提前终止文本字符串,然后追加一个新的命令。如以直接注入式攻击为例。
就是在用户输入变量的时候,先用一个分号结束当前的语句。然后再插入一个恶意SQL语句即可。
由于插入的命令可能在执行前追加其他字符串,因此攻击者常常用注释标记“—”来终止注入的字符
串。执行时,系统会认为此后语句位注释,故后续的文本将被忽略,不背编译与执行。
4、SQL注入攻击的简单示例:
这里我们举一个比较常见的例子来简要说明一下sql注入的原理。假如我们有一个users表,里
面有两个字段username和password。在我们的java代码中我们初学者都习惯用sql拼接的方式进行
用户验证。比如:"select id from users where username = '"+username +"' and password = '" +
password +"'" 这里的username和password都是我们存取从web表单获得的数据。下面我们来看一
下一种简单的注入,如果我们在表单中username的输入框中输入' or 1=1-- ,password的表单中
随便输入一些东西,假如这里输入123.此时我们所要执行的sql语句就变成了select id from users
where username = '' or 1=1-- and password = '123',我们来看一下这个sql,因为1=1是true,
后面 and password = '123'被注释掉了。所以这里完全跳过了sql验证。
二、如何防御sql注入攻击
1.采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。
使用好处:
(1).代码的可读性和可维护性.
(2).PreparedStatement尽最大可能提高性能.
(3).最重要的一点是极大地提高了安全性.
[java] view plain copy
<span style="font-size:14px;">String sql= "select * from users where username=? and password=?;
PreparedStatement preState = conn.prepareStatement(sql);
preState.setString(1, userName);
preState.setString(2, password);
ResultSet rs = preState.executeQuery(); </span>
原理:sql注入只对sql语句的准备(编译)过程有破坏作用,而PreparedStatement已经准备好了,执行阶
段只是把输入串作为数据处理,而不再对sql语句进行解析,准备,因此也就避免了sql注入问题.
2.使用正则表达式过滤传入的参数
正则表达式:
private String CHECKSQL = “^(.+)\\sand\\s(.+)|(.+)\\sor(.+)\\s$”;
判断是否匹配:
Pattern.matches(CHECKSQL,targerStr);
下面是具体的正则表达式:
检测SQL meta-characters的正则表达式 :
/(\%27)|(\’)|(\-\-)|(\%23)|(#)/ix
修正检测SQL meta-characters的正则表达式 :/((\%3D)|(=))[^\n]*((\%27)|(\’)|(\-\-)|(\%3B)|()/i
典型的SQL 注入攻击的正则表达式 :/\w*((\%27)|(\’))((\%6F)|o|(\%4F))((\%72)|r|(\%52))/ix
检测SQL注入,UNION查询关键字的正则表达式 :/((\%27)|(\’))union/ix(\%27)|(\’)
检测MS SQL Server SQL注入攻击的正则表达式:
/exec(\s|\+)+(s|x)p\w+/ix
等等…..
其实可以简单的使用replace方法也可以实现上诉功能:
public static String TransactSQLInjection(String str)
{
return str.replaceAll(".*([';]+|(--)+).*", " ");
}
3.字符串过滤
比较通用的一个方法:
(||之间的参数可以根据自己程序的需要添加)
- [java] view plain copy
- <span style="font-size:14px;">public static boolean sql_inj(String str)
- {
- String inj_str = "'|and|exec|insert|select|delete|update|
- count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
- String inj_stra[] = split(inj_str,"|");
- for (int i=0 ; i < inj_stra.length ; i++ )
- {
- if (str.indexOf(inj_stra[i])>=0)
- {
- return true;
- }
- }
- return false;
- }</span>
复制代码
4.jsp中调用该函数检查是否包函非法字符
-
- 防止SQL从URL注入:
- sql_inj.java代码:
- [java] view plain copy
- <span style="font-size:14px;">package sql_inj;
- import java.net.*;
- import java.io.*;
- import java.sql.*;
- import java.text.*;
- import java.lang.String;
- public class sql_inj{
- public static boolean sql_inj(String str)
- {
- String inj_str = "'|and|exec|insert|select|delete|update|
- count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+|,";
- //这里的东西还可以自己添加
- String[] inj_stra=inj_str.split("\\|");
- for (int i=0 ; i < inj_stra.length ; i++ )
- {
- if (str.indexOf(inj_stra[i])>=0)
- {
- return true;
- }
- }
- return false;
- }
- } </span>
复制代码
5.JSP页面添加客户端判断代码:
使用javascript在客户端进行不安全字符屏蔽
功能介绍:检查是否含有”‘”,”\\”,”/”
参数说明:要检查的字符串
返回值:0:是1:不是
函数名是
- [java] view plain copy
- <span style="font-size:14px;">function check(a)
- {
- return 1;
- fibdn = new Array (”‘” ,”\\”,”/”);
- i=fibdn.length;
- j=a.length;
- for (ii=0; ii<i; ii++)
- { for (jj=0; jj<j; jj++)
- { temp1=a.charAt(jj);
- temp2=fibdn[ii];
- if (tem’; p1==temp2)
- { return 0; }
- }
- }
- return 1;
- } </span>
复制代码
|
|