网站地图    收藏   

主页 > 后端 > 网站安全 >

利用PostgreSQL的$q$逃逸语法提高数据库程序逃逸长

来源:自学PHP网    时间:2015-04-17 10:15 作者: 阅读:

[导读] 前言在我们的数据库应用里,为了避免SQL注入的攻击,应用通常需要对生成的SQL字串进行转义,也就是对组成字串的变量中的单引号进行转义,通常是写成双份,比如: select * from tabl...

前言

在我们的数据库应用里,为了避免SQL注入的攻击,应用通常需要对生成的SQL字串进行转义,也就是对组成字串的变量中的单引号进行转义,通常是写成双份,比如:

  select * from table_name where name = $var;

假如 $var 是

 laser's database

那么要将其转义成:

 laser''s database

这样最后的 SQL 字串是这样的:

  select * from table_name where name = 'laser''s database';

这样,数据库通常要对整个输入串进行扫描,在输入串很长的时候,性能确实比较差,而且,更糟糕的是,在集群环境里,SQL串是通过 proxy 以字串的形式广播给所有节点进行查询的,那么这个时候的转义可能会变得很复杂:proxy需要一层转义,而还要兼顾各个节点自身是否需要转义的问题,尤其是在proxy和节点之间的协议是二进制和字符协议混合的时候,简直会让人抓破脑袋。

 名词解释: SQL 注入(SQL inject),是通过某种手段可以让数据库执行意外的查询。比如,上面的查询输入一个: '';delete from table_name; 这样的字串,那么如果不对 $var 加以转义,前面的 SQL 会变成这样:select * from table_name where name ='';delete from table_name; 这个就等于删除了你的table_name表的所有内容!!!

分析问题

那么,这个问题除了扫描字串进行转义之外,就没有别的方法了么?答案当然是“有其他方法”!

对于 PostgreSQL 来说,我们可以利用 PostgreSQL 特有的 $ 引号表示法,接合好的散列算法,实现免转义的功能!

用一句话来描述的话,就是我们用SQL自身的散列值,做$引号的内容,以此来避免扫描和多层转义的问题。

 解法

$(美元符引号

PostgreSQL 的$(美元符)引号表示法的是这样的:

所有在$和$之间的,以字母开头,包含字母数字的东西,都会被 PostgreSQL 看作是单引号的替代品,比如下面这些都是$(美元符)引号:

  $q$
  $func$
  $string$
  $q0123456789ABCDEF$

使用$(美元符)引号的时候,用其包围的字串内的单引号可以不用转义,比如我们经常这样写函数定义:

CREATE OR REPLACE FUNCTION myQuote(integer) returns integer as
$$
 select id from table_name where name = $q$laser's function$q$ limit $1;
$$ language sql;

注意里面字串的的 laser' function 中的单引号并没有使用 quote_literal() 函数进行转义,而是直接用 $q$ 做引号包围起来;这样我们的代码可以省略很多难懂的单引号。对比一下下面的不用$引号表示法的版本:

CREATE OR REPLACE FUNCTION myQuote(integer) returns integer as
'
 select id from table_name where name = ''laser''''s function'' limit $1;
' language sql;

上面的单引号数目已经足以让人崩溃了,如果我们再想想通过另外一个字串传递进来。。。。

避免自身被命中

$引号乍一看只是为了减少单引号的使用量,但是其自身并不意味着就不用做任何转义,因为只要文本内容中出现了$引号,那么它自己也是需要转义的,比如下面这样的:

 select $$laser's\$\$$$;

是不能通过分析器的。这个时候我们必须选取一个在查询文本中不会出现的东西放在$引号中间,比如,上面那个例子可以这么写:

  select $q$laser's $$$q$;

现在问题来了,在用户可能输入任何东西的情况下,我们如何才能利用好这个特性呢?

进入脑海的真是散列算法,比如,md5,其实我们可以这样设计自己的$引号:

 $q||md5(raw sql string)||$

也就是说,一个$(美元符),后面跟着一个字母q,后面跟着裸SQL串计算出来的md5值的文本形式(HEX转义),后面再跟着一个 $(美元符)组成我们的$引号。

实例

我们举一个例子,还是拿上面的 select * from table_name where name = $var; 来说,假如 $var 的数值是:

  laser's $quote

那么

 md5(laser's $quote)=a4f09eb303320f5529b7a3d8d6869dc6

于是,我们的字串文本的$引号会是:

 $qa4f09eb303320f5529b7a3d8d6869dc6$

然后,我们的裸SQL字串会是这个:

  select * from table_name where name = $qa4f09eb303320f5529b7a3d8d6869dc6$laser's $quote$qa4f09eb303320f5529b7a3d8d6869dc6$

计算上面这个串的md5值,得到:

  29750c173eee666ee4b9ca11f02c4dc5

于是整个SQL串的SQL文本表现形式为:

$q29750c173eee666ee4b9ca11f02c4dc5$select * from table_name where name = $qa4f09eb303320f5529b7a3d8d6869dc6$laser's $quote$qa4f09eb303320f5529b7a3d8d6869dc6$$q29750c173eee666ee4b9ca11f02c4dc5$


在人看来,这个串看上去似乎很别扭。但是机器却能够很好地处理它:

laser=# select $q29750c173eee666ee4b9ca11f02c4dc5$select * from table_name where name = 
$qa4f09eb303320f5529b7a3d8d6869dc6$laser's $quote$qa4f09eb303320f5529b7a3d8d6869dc6$$q29750c173eee666ee4b9ca11f02c4dc5$;
                                                          ?column?                                                          
------------------------------------------------------------------------------------------------------------
 select * from table_name where name = $qa4f09eb303320f5529b7a3d8d6869dc6$laser's $quote$qa4f09eb303320f5529b7a3d8d6869dc6$
(1 笔资料列)

而且这样我们也可以直接避免转义了,很多场合下,我们可以不需要调用 quote 系列函数。

理论分析

为什么这样我们就可以避免转义呢?其实我们只是充分利用了散列算法的低碰撞概率的特性,众所周知,MD5 会生成128位的一个数值,理论上其碰撞概率应该是接近1/2^128,最近山东大学王小云教授证明这个碰撞概率比这个高多了,大概是在 1/2^96 左右,但是这个概率,对我们99.9999%的应用来说,依然是极低极低的;而且,我们未必一定要用MD5,也可以用更安全的 SHA 等算法,这样可以在$引号长度相同的情况下,获得超越 6σ的可靠性。

最后说两句性能,无论怎样,扫描还是要至少扫描一次的,但是长字串的扫描要远快于单字符的扫描,并且,MD5算法是块运算,一次读取16个字节,这方面,也会有一定的性能提升。

取自"http://www.pgsqldb.org:8079/mwiki/index.php/%E5%88%A9%E7%94%A8PostgreSQL%E7%9A%84%24q%24%E9%80%83%E9%80%B8%E8%AF%AD%E6%B3%95%E6%8F%90%E9%AB%98%E6%95%B0%E6%8D%AE%E5%BA%93%E7%A8%8B%E5%BA%8F%E9%80%83%E9%80%B8%E9%95%BF%E6%96%87%E6%9C%AC%E6%80%A7%E8%83%BD"

自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习

京ICP备14009008号-1@版权所有www.zixuephp.com

网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com

添加评论