html防sql注入,常见漏洞防御 之 防SQL注入的三种方式

b0391aebd26e4f6818babd046706c925.png

看以下三种SQL语句

String sql1 = "select * from user where username = '"+username+"' and password = '"+password+"'";

String sql2 ="select * from user where username = :username and password = :password";

String sql3 = "select * from user where username = ? and password = ?";

推荐写法是sql2、sql3使用的别名或者通配符的形式进行传值,可以避免SQL注入,sql1就有了常见的典型SQL注入问题,假设username随便传个值,比如 '张三',传入的password的值为 ' or 1 = 1' 则 拼接的SQL语句成了

select * from user where username ='张三' and password = '' or 1 = 1 ''

很明显无论前面的and为真还是假,只要or后面为真,则就可使查询为true,导致SQL注入 所以尽可能避免字符串拼接的形式进行SQL传值,但有些场景可能必须采用字符串拼接的形式,比如Mybatis在按要求排序时:

order by #{order} #{sort}

用 #{}的形式取值就相当于字符串拼接,但是因为排序DESC、AESC这种是SQL关键字,不能进行转义,所以就必须采用字符串拼接的形式了

如果采用这种形式还要避免SQL注入的话,就需要对传入的值进行SQL过滤,来避免SQL注入

那么OWASP提供了一个防御sql注入的Esapi包,这个包中的encodeForSQL方法能对sql注入进行很好的防御。

//防止Oracle注入

ESAPI.encoder().encodeForSQL(new OracleCodec(),queryparam)

//防止mysql注入

ESAPI.encoder().encodeForSQL(new MySQLCodec(Mode.STANDARD),queryparam) //Mode.STANDARK为标准的防注入方式,mysql一般用使用的是这个方式

//防止DB2注入 ESAPI.encoder().encodeForSQL(new DB2Codec(),queryparam)

使用不同的数据库,使用的过滤方法不同

下面我们就用MySQL为例字分析encodeForSQL函数做了什么防御。具体函数过程就不跟踪了,直接分析最后调用了哪个方法。根据代码可知最后调用的是encodeCharacter方法。

public String encodeCharacter( char[] immune, Character c ) {

char ch = c.charValue();

// check for immune characters

if ( containsCharacter( ch, immune ) ) {

return ""+ch;

}

// check for alphanumeric characters

String hex = Codec.getHexForNonAlphanumeric( ch );

if ( hex == null ) {

return ""+ch;

}

switch( mode ) {

case ANSI: return encodeCharacterANSI( c );

case STANDARD: return encodeCharacterMySQL( c );

}

return null;

}

上述方法中containsCharacter函数是不进行验证的字符串白名单,Codec.getHexForNonAlphanumeric函数查找字符传中是否有16进制,没有返回空值。

而encodeCharacterANSI和encodeCharacterMySQL才是防御的重点,我们看一下这两个函数的不同,如果选择的我们选择是Mode.ANSi模式,则字符串则进入下面的函数,可以看到这个函数对单撇号和双撇号进行了转义。

private String encodeCharacterANSI( Character c ) {

if ( c == '\'' )

return "\'\'";

if ( c == '\"' )

return "";

return ""+c;

}

如果选择的是Mode.STANDARD模式,则字符串则进入下面的函数,可以看到这个函数对单撇号和双撇号、百分号、反斜线等更多的符号进行了转换,所以使用时推荐使用标准模式。

private String encodeCharacterMySQL( Character c ) {

char ch = c.charValue();

if ( ch == 0x00 ) return "\\0";

if ( ch == 0x08 ) return "\\b";

if ( ch == 0x09 ) return "\\t";

if ( ch == 0x0a ) return "\\n";

if ( ch == 0x0d ) return "\\r";

if ( ch == 0x1a ) return "\\Z";

if ( ch == 0x22 ) return "\\\"";

if ( ch == 0x25 ) return "\\%";

if ( ch == 0x27 ) return "\\'";

if ( ch == 0x5c ) return "\\\\";

if ( ch == 0x5f ) return "\\_";

return "\\" + c;

}

写个单元测试:

@org.junit.Test

public void testESAPI() {

String username = "zhangsan"; String password = "' or 1=1'";

String sql1 = "select * from user where username = '"+username+"' and password = '"+password+"'";

//String sql2 ="select * from user where username = :username and password = :password";

//String sql3 = "select * from user where username = ? and password = ?";

System.out.println("过滤前:"+sql1);

username = ESAPI.encoder().encodeForSQL(new MySQLCodec((Mode.STANDARD)), username);

password = ESAPI.encoder().encodeForSQL(new MySQLCodec((Mode.STANDARD)), password);

sql1 = "select * from user where username = '"+username+"' and password = '"+password+"'";

System.out.println("过滤后:"+sql1);

}

我们介绍了利用绑定变量、通配符和利用esapi三种方式对sql注入进行防御,我的建议是尽量使用绑定变量或者通配符的是形式进行防注入,安全性能都比较好,如果不得不使用字符串拼接的形式,则使用esapi进行sql过滤

最后给个esapi的maven支持形式

org.owasp.esapi

esapi

2.1.0.1

Q.E.D.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值