SQL注入的原理
利用数据库对特殊标识符的解析强行从页面向后台传入,改变SQL语句结构,达到扩展权限、创建高等级用户、强行修改用户资料等操作。所谓的SQL注入,就是通过把SQL命令插入到web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。
对于java数据库连接JDBC而言,SQL注入攻击只对Statement有效,对PreparedStatement是无效的,这是因为PreparedStatement不允许在不同的插入时间改变查询的逻辑结构。
如验证用户是否存在的SQL语句为: 用户名’and pswd=’密码
如果在用户名字段中输入: ‘or 1=1或是在密码字段中输入:’or 1=1
将绕过验证,但这种手段只对只对Statement有效,对PreparedStatement无效。
如何判断是否被sql注入了呢?
判断SQL注入可以通过页面传入的数据,后台不应该相信从后台传入的任何数据,特别是特殊整型参数和特殊字符参数。
什么是字符串拼接得到的
String sql=”select id,no from user where id=”+id;
SQL注入:是一种将sql代码添加到输入参数中,传递到SQL服务器解析并执行的一种攻击方法。
数字注入
select * from tablename where id=1 or 1=1;
字符串注入
select * from tablename where user_name="miss" # and password='12345678';
select * from tablename where user_name="miss"-- and password='12345678';
#
与 - - 号后面的被注释掉,无论密码输入的是什么,都能正确查询
我们举一个比较常见的例子来简要说明一下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注入其实也很简单 ,SQL注入漏洞存在的原因,就是拼接SQL参数,也就是将用于输入的查询参数,直接拼接在SQL语句中,导致了SQL注入漏洞。
1.采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。
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();
原理: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.字符串过滤
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;
}
4.jsp中调用该函数检查是否包含非法字符(防止SQL从URL注入)
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;
}
5.JSP页面添加客户端判断代码:使用javascript在客户端进行不安全字符屏蔽
功能介绍:检查是否含有”‘”,”\”,”/”
参数说明:要检查的字符串
返回值:0:是1:不是
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 (temp1==temp2) {
return 0;
}
}
}
return 1;
}