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

本贴最后更新于 2944 天前,其中的信息可能已经时移世易

看以下三种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 = ?";</pre>

 

推荐写法是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; } </pre>

 

上述方法中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); }</pre>

 

SQL注入

 

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

最后给个esapi的maven支持形式

	<dependency>
			<groupId>org.owasp.esapi</groupId>
			<artifactId>esapi</artifactId>
			<version>2.1.0.1</version>
		</dependency>

 

 

 

 

 

  • SQL
    128 引用 • 390 回帖 • 3 关注
  • 安全

    安全永远都不是一个小问题。

    203 引用 • 818 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • AWS
    11 引用 • 28 回帖 • 9 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    87 引用 • 139 回帖 • 1 关注
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 60 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 639 关注
  • V2Ray
    1 引用 • 15 回帖 • 1 关注
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    76 引用 • 258 回帖 • 630 关注
  • 正则表达式

    正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列遵循某个句法规则的字符串。

    31 引用 • 94 回帖
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    133 引用 • 888 回帖 • 1 关注
  • 钉钉

    钉钉,专为中国企业打造的免费沟通协同多端平台, 阿里巴巴出品。

    15 引用 • 67 回帖 • 297 关注
  • gRpc
    11 引用 • 9 回帖 • 90 关注
  • 导航

    各种网址链接、内容导航。

    43 引用 • 177 回帖 • 2 关注
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖
  • 创造

    你创造的作品可能会帮助到很多人,如果是开源项目的话就更赞了!

    183 引用 • 1010 回帖
  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 488 关注
  • VirtualBox

    VirtualBox 是一款开源虚拟机软件,最早由德国 Innotek 公司开发,由 Sun Microsystems 公司出品的软件,使用 Qt 编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。

    10 引用 • 2 回帖 • 13 关注
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    289 引用 • 4492 回帖 • 653 关注
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 384 回帖 • 1 关注
  • Ruby

    Ruby 是一种开源的面向对象程序设计的服务器端脚本语言,在 20 世纪 90 年代中期由日本的松本行弘(まつもとゆきひろ/Yukihiro Matsumoto)设计并开发。在 Ruby 社区,松本也被称为马茨(Matz)。

    7 引用 • 31 回帖 • 253 关注
  • OpenResty

    OpenResty 是一个基于 NGINX 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

    17 引用 • 55 关注
  • 创业

    你比 99% 的人都优秀么?

    82 引用 • 1395 回帖 • 2 关注
  • 前端

    前端技术一般分为前端设计和前端开发,前端设计可以理解为网站的视觉设计,前端开发则是网站的前台代码实现,包括 HTML、CSS 以及 JavaScript 等。

    245 引用 • 1338 回帖
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 5 关注
  • Anytype
    3 引用 • 31 回帖 • 12 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖
  • SQLite

    SQLite 是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的 SQL 数据库引擎。SQLite 是全世界使用最为广泛的数据库引擎。

    5 引用 • 7 回帖
  • PWA

    PWA(Progressive Web App)是 Google 在 2015 年提出、2016 年 6 月开始推广的项目。它结合了一系列现代 Web 技术,在网页应用中实现和原生应用相近的用户体验。

    14 引用 • 69 回帖 • 175 关注
  • OneNote
    1 引用 • 3 回帖