早在2006年,有个老外写了一篇blog,说明了在GBK编码环境下addslashes函数对预防sql注入失效的问题:
[1] http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string
简要地说就是:
在GBK编码中,0xbf27是无效字符,但0xbf5c是,注意0x27(')和0x5c(\)
用addslashes处理0xbf27,会得到0xbf5c27 ,即本来没有单引号的,处理完末尾却多了一个单引号。。。
上文中作者的建议是使用mysql_real_escape_string,但这个函数蜀国使用不当,仍无法避免前述问题,具体见:
[2] />
简要地说就是: 如果通过sql语句来设置字符集,那么对于提交该sql之前已经创建的Mysql连接,其中的字符集信息并未被修改,如果此时使用
mysql_real_escape_string,仍不能避免上述风险;
从前述文1和文2正文以及评论中看,终极的方案是使用PDO,即使sql只提交一次,缺点是会稍微慢一点点
关于这个问题,还看到了有用户吐槽thinkphp的不负责任:
[3] />
看到这个后,查了一下正在使用的tp框架,版本也是3.1.2,上面的问题代码赫然存在。。。
引用一段文3中贴主的一个总结:
个人认为最简单、有效、方便的避免SQL注入。就是采用php官方说的pdo参数绑定。1.提高的SQL执行效率。2.彻底避免了SQL注入(1.php版本要正确、2.关闭本地转义)
所以,真正安全的处理方式是这样的:
按照http://zhangxugg-163-com.iteye.com/blog/1835721说的那样
1. php升级到5.3.6+,生产环境强烈建议升级到php 5.3.9+ php 5.4+,php 5.3.8存在致命的hash碰撞漏洞。
2. 若使用php 5.3.6+, 请在在PDO的DSN中指定charset属性
3. 如果使用了PHP 5.3.6及以前版本,设置PDO::ATTR_EMULATE_PREPARES参数为false(即由MySQL进行变量处理),php 5.3.6以上版本已经处理了这个问题,无论是使用本地模拟prepare还是调用mysql server的prepare均可。在DSN中指定charset是无效的,同时set names <charset>的执行是必不可少的。
关于为什么使用PDO可以方式sql注入的问题,下面这篇博文做了一些分析:
http://zhangxugg-163-com.iteye.com/blog/1835721
关于这个问题的详细、全面的分析,看stackoverflow上面的这个讨论:
/>
阅读(393) | 评论(0) | 转发(0) |