上周给别人做了个网站无意间发现自己的作品有很多漏洞在短短的秒就被自己用sql注入法给干了所以查了一点关于sql注入的资料并且有点感悟希望能与新手们分享一下高手们见笑了!
SQL注入攻击的总体思路
发现SQL注入位置
判断服务器类型和后台数据库类型
确定可执行情况
对于有些攻击者而言一般会采取sql注入法下面我也谈一下自己关于sql注入法的感悟
注入法
从理论上说认证网页中会有型如
select * from admin where username=XXX and password=YYY 的语句若在正式运行此句之前如果没有进行必要的字符过滤则很容易实施SQL注入
如在用户名文本框内输入abc or = 在密码框内输入 则SQL语句变成
select * from admin where username=abc or = and password= 不管用户输入任何用户名与密码此语句永远都能正确执行用户轻易骗过系统获取合法身份
猜解法
基本思路是猜解所有数据库名称猜出库中的每张表名分析可能是存放用户名与密码的表名猜出表中的每个字段名猜出表中的每条记录内容
还有一种方式可以获得你的数据库名和每张表的名
就是通过在形如;/news?id=的方式来通过报错获得你的数据库名和表名!
对于jsp而言我们一般采取一下策略来应对
PreparedStatement
如果你已经是稍有水平开发者你就应该始终以PreparedStatement代替Statement
以下是几点原因
代码的可读性和可维护性
PreparedStatement尽最大可能提高性能
最重要的一点是极大地提高了安全性
到目前为止有一些人(包括本人)连基本的恶义SQL语法都不知道
String sql = select * from tb_name where name= +varname+ and passwd=+varpasswd+;
如果我们把[ or = ]作为name传入进来密码随意看看会成为什么?
select * from tb_name = or = and passwd = 随意 ;
因为=肯定成立所以可以任何通过验证更有甚者:
把[;drop table tb_name;]作为varpasswd传入进来则:
select * from tb_name = 随意 and passwd = ;drop table tb_name;有些数据库是不会让你成功的但也有很多数据库就可以使这些语句得到执行
而如果你使用预编译语句你传入的任何内容就不会和原来的语句发生任何匹配的关系(前提是数据库本身支持预编译但上前可能没有什么服务端数据库不支持编译了只有少数的桌面数据库就是直接文件访问的那些只要全使用预编译语句你就用不着对传入的数据做任何过虑而如果使用普通的 statement有可能要对drop;等做费尽心机的判断和过虑
正则表达式
检测SQL metacharacters的正则表达式 /(\%)|(\)|(\\)|(\%)|(#)/ix
修正检测SQL metacharacters的正则表达式 /((\%D)|(=))[^\n]*((\%)|(\)|(\\)
|(\%B)|(:))/i
典型的 SQL 注入攻击的正则表达式 /\w*((\%)|(\))((\%F)|o|(\%F))((\%)|r|(\
%))/ix
检测SQL注入UNION查询关键字的正则表达式 /((\%)|(\))union/ix(\%)|(\) 单
引号和它的hex等值union union关键字
检测MS SQL Server SQL注入攻击的正则表达式 /exec(\s|\+)+(s|x)p\w+/ix
字符串过滤
public static String filterContent(String content){
String flt =|and|exec|insert|select|delete|update|count|*|%
|chr|mid|master|truncate|char|declare|;|or||+|;
Stringfilter[] = fltsplit(|);
for(int i=;i<filterlength ; i++)
{
contentreplace(filter[i] );
}
return content;
}
不安全字符屏蔽
本部分采用js来屏蔽起的作用很小这样用屏蔽关键字的方法虽然有一定作用但是在实际应用中这些 SQL的关键字也可能成为真正的查询关键字到那是被你屏蔽了那用户不是不能正常的使用了只要在代码规范上下点功夫就可以了
凡涉及到执行的SQL中有变量时用JDBC(或者其他数据持久层)提供的如PreparedStatement就可以切记不要用拼接字符串的方法就可以了
功能介绍检查是否含有\\/
参数说明要检查的字符串
返回值是 不是
函数名是
function check(a)
{
return ;
fibdn = new Array ( \\/);
i=fibdnlength;
j=alength;
for (ii=;ii<i;ii++)
{ for (jj=;jj<j;jj++)
{ temp=acharAt(jj);
temp=fibdn[ii];
if (tem;p==temp)
{ return ; }
}
}
return ;
}