sql注入的原理与应对
sql注入是黑客通过代码注入(前端表单、URL等),攻击数据库的一种手段。简单的说,可以将数据库语句区分成编译前和编译后两种状态,sql注入攻击数据库,只对编译前的sql有作用。
举个栗子:一个校验用户登入的sql语句。
SELECT id,name FROM user where username = 'A' and password = 'B';
其中A和B是传入的参数,正常情况通过该语句进行密码校验没啥问题。
假设A的参数被人拦截,模拟数据请求 A 的值设为 ' or 1=1 -- 那么该语句将变成 ;
SELECT id,name FROM user where name = '1' or 1=1 -- and password = 'B';
从图中可以很明细的看出 -- 后的语句被注释掉,同时通过or 1=1 可以查询出所有的账号和密码 ,轻而易举的登入系统,当然这只是一个简单的例子,如果将A替换成 '; drop XXX,可以将整个数据库删除。
SELECT id,name FROM user where name = '1'; drop XXX -- and password = 'B';
以下简单介绍几种防sql注入的方法,知道了sql注入的原理我们可以通过避免这类语句的插入来达到防注入的目的:
1、简单通过,正则表达式和字符串过滤等,过滤掉存在 ‘ 、-- 、;、等这里字符串。
private String CHECKSQL = “^(.+)\\sand\\s(.+)|(.+)\\sor(.+)\\s$”;
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;
}
2、也可以通过js前端校验表单提交的数据内容。
3、通过jdbc预编译好的sql语句进行防注入,通过 占位符 ?,通过参数传递的方式,编译后的语句无法进行sql注入。
String sql= "select * from user where username=? and password=?;
PreparedStatement preState = conn.prepareStatement(sql);
preState.setString(1, userName);
preState.setString(2, password);
ResultSet rs = preState.executeQuery();
采用预编译语句集,它内置了处理SQL注入的能力,只要使用它的setXXX方法传值即可。
使用好处:
- 代码的可读性和可维护性.
- PreparedStatement尽最大可能提高性能.
- 最重要的一点是极大地提高了安全性.
原理:
- sql注入只对sql语句的准备(编译)过程有破坏作用
- 而PreparedStatement已经准备好了,执行阶段只是把输入串作为数据处理,
- 而不再对sql语句进行解析,准备,因此也就避免了sql注入问题.
4、通过调用现有的框架,hibernate、mybatis他们已经内置过滤了部分的sql注入。
通过mybatis调用数据库,用#进行参数传递,他可以事先将sql语句编译好,通过占位符 ?进行参数传递,编译后的sql是无法进行sql注入的。我们开发时应尽量使用 # ,在开发中对于表名、字段名不可避免的用到$ 进行参数传递,由于他是后编译的,我们应在参数传递时做好字符过滤。