ID:-

所有对Web应用的攻击都要传入有害的参数,因此代码安全的基础就是对传入的参数进行有效的过滤,比如像SQL注入漏洞,只要过滤到单引号,就能防御住大部分的类型的SQL注入,只要过滤掉尖括号和单双引号也能过滤掉不少XSS漏洞,这种简单的过滤跟完全不过滤带来的效果是天壤之别,我们做的就是要细化这些过滤规则,通过横向扩展防御策略来拦截更多的攻击,不少第三方提供了这样的过滤函数和类,我们可以直接引用,另外PHP自身提供了不少过滤的函数,好好使用这些内置的函数也能达到非常好的效果。

一、第三方过滤函数与类

在一些中小型的Web应用程序中,由于大多数开发者是不怎么懂安全的,所以都会选择一些第三方的过滤函数或者类,直接拿过去套着用,并不知道效果到底怎么样。在PHP安全过滤的类里面,比较出名的有出自80sec团队给出的一个SQL注入过滤的类,在国内大大小小的程序像、、等都使用过。

目前大多数应用都有一个参数过滤的统一入口,类似于的代码,如下所示:

(Array('_GET','_POST','')as $)

($$ as $_k => $_v)

if($_k == '')${$_k} = $_v;

else ${$_k} = ($_v);

跟进()函数之后的代码如下:

(&$svar)

if(!())

if(($svar))

($svar as $_k => $_v)$svar[$_k] = ($_v);

else

if(($svar)>0&& ('#^(cfg_||_GET|_POST|)#',$svar))

exit(' var not allow!');

$svar = ($svar);

$svar;

而这里仅仅是使用()函数过滤,确实能防御住一部分漏洞,但是对特定的场景和漏洞就不那么好使了。所以除了总入口,在具体的功能点也需要进行一些过滤。

(一) SQL安全过滤类分析

全称 !Board,是一套开源通用的社区论坛软件系统dedecms标签,使用PHP+MySQL开发,由于用户量巨大,一直是众多安全爱好者重点研究的对象,所以也被公布过不少的安全漏洞。经过数年的沉淀,如今的主程序在代码安全方面已经做得比较成熟。

在专门有一个SQL注入过滤类来过滤SQL注入请求,不过也出现了多次绕过的情况,下面我们来分析它的这个SQL注入过滤的类。

首先我们先看到的配置文件//.php中的“ ”部分内容,如下:

// ------------------------- -------------------------- //

$[''][''] = '';

$[''][''] = 1;

$[''][''] = '0';

$[''][''][''] = 1;

//是否开启SQL注入防御//

以下是过滤规则

$['']['']['']['0'] = '';

$['']['']['']['1'] = 'hex';

$['']['']['']['2'] = '';

$['']['']['']['3'] = 'if';

$['']['']['']['4'] = 'ord';

$['']['']['']['5'] = 'char';

$['']['']['']['0'] = '@';

$['']['']['']['1'] = '';

$['']['']['']['2'] = '';

$['']['']['']['3'] = '';

$['']['']['']['4'] = '(';

$['']['']['']['5'] = '';

$['']['']['']['6'] = '';

$['']['']['dnote']['0'] = '/*';

$['']['']['dnote']['1'] = '*/';

$['']['']['dnote']['2'] = '#';

$['']['']['dnote']['3'] = '--';

$['']['']['dnote']['4'] = '"';

$[''][''][''] = 1;

$[''][''][''] = '0';

我们可以看到配置文件中可以设置是否开启SQL注入防御,这个选项默认开启,一般不会有管理员去关闭,再往下的内容:

$['']['']['']

以及

$['']['']['dnote']

都是SQL注入过滤类的过滤规则,规则里包含了常见的注入关键字。

执行SQL语句之前会调用\class\.php文件check类下面的($sql)函数进行过滤,我们来跟进这个函数看看,代码如下:

($sql)

if(self::$ === null)

self::$ = ('//');

if(self::$[''])

$check = 1;

$cmd = ((trim($sql),,3));

if(isset(self::$[$cmd]))

$check = self::($sql);

(($cmd,,2)=== '/*')

$check = -1;

if($check < 1)

throw new ('It is not safe to do this query',,$sql);

true;

从代码中可以看到,程序首先加载配置文件中的//,根据$['']判断SQL注入防御是否开启,再到$check=self::($sql);可以看到该函数又调用了同类下的()函数对SQL语句进行过滤,我们继续跟进()函数,代码如下:

($sql)

$sql = (array('\\','\'','\"',''''),'',$sql);

$mark = $clean = '';

if(($sql,'/')=== false && ($sql,'#')=== false && ($sql,'-- ')=== false && ($sql,'@')=== false && ($sql,'`')=== false)

$clean = ("/'(.+?)'/s",'',$sql);

else

$len = ($sql);

$mark = $clean = '';

for($i = 0;$i < $len;$i++)

$str = $sql[$i];

($str)

case '`':if(!$mark)

$mark = '`';

$clean .= $str;

($mark == '`')

$mark = '';

break;

case ''':

if(!$mark)

$mark = ''';

$clean .= $str;

($mark == ''')

$mark = '';

break;

case '/':

if(empty($mark)&& $sql[$i + 1] == '*')

$mark = '/*';

$clean .= $mark;

$i++;

($mark == '/*' && $sql[$i - 1] == '*')

$mark = '';

$clean .= '*';

break;

case '#':

if(empty($mark))

$mark = $str;

$clean .= $str;

break;

case "n":

if($mark == '#' || $mark == '--')

$mark = '';

break;

case '-':

if(empty($mark)&& ($sql,$i,3)== '-- ')

$mark = '-- ';

$clean .= $mark;

break;

break;

$clean .= $mark?'':$str;

if(($clean,'@')!== false)

'-3';

$clean = ("/[^a-z0-9_-()#*/"]+/is","",($clean));

if(self::$[''])

$clean = ('/**/','',$clean);

if((self::$['']))

(self::$[''] as $fun)

if(($clean,$fun . '(')!== false)

'-1';

if((self::$['']))

(self::$[''] as $)

if(($clean,$)!== false)

'-3';

if(self::$[''] && ($clean,''))

'-2';

if((self::$['dnote']))

(self::$['dnote'] as $note)

if(($clean,$note)!== false)

'-4';

1;

从如上代码我们可以看到,该函数首先使用:

$sql = (array('\\','\'','\"',''''),'',$sql);

将SQL语句中的\、'、"以及''替换为空,紧接着是一个if else判断逻辑来选择过滤的方式:

if(($sql,'/')=== false && ($sql,'#')=== false && ($sql,'-- ')=== false && ($sql,'@')=== false && ($sql,'`')=== false)

$clean = ("/'(.+?)'/s",'',$sql);

else

这段代码表示当SQL语句里存在'/'、#'、'--'、'@'、'`'这些字符时,则直接调用()函数将单引号(')中间的内容替换为空,这里之前存在一个绕过,只要把SQL注入的语句放到单引号中间,则会被替换为空,进行下面再判断的时候已经检测不到SQL注入的关键字,导致绕过的出现,在MySQL中使用@`'`代表null,SQL语句可以正常执行。

else条件中是对整段SQL语句进行逐个字符进行判断,比如:

case '/':

if(empty($mark)&& $sql[$i + 1] == '*')

$mark = '/*';

$clean .= $mark;

$i++;

($mark == '/*' && $sql[$i - 1] == '*')

$mark = '';

$clean .= '*';

break;

这段代码的逻辑是,当检查到SQL语句中存在斜杠(/)时,则去判断下一个字符是不是星号(*),如果是星号(*)就把这两个字符拼接起来,即/*,然后继续判断下一个字符是不是星号(*),如果是星号则再继续拼接起来,得到/**,最后在如下代码中判断是否存在原来拦截规则里面定义的字符,如果存在则拦截SQL语句执行:

if((self::$['dnote']))

(self::$['dnote'] as $note)

if(($clean,$note)!== false)

'-4';

国内知名的多款cms应用如等,都有使用类似这个过滤类,另外由于应用的基础架构不一样,这个过滤类应用起来的实际效果也各不太一样,目前做得相对较好。

(二) XSS标签过滤函数分析

目前大多数XSS过滤都是基于黑名单的形式,编程语言和编码结合起来千变万化,基于黑名单的过滤总给人不靠谱的感觉,事实确实是这样dedecms标签,目前好像还没有看到基于黑名单过滤的规则一直没有被绕过,其实在XSS的防御上,只要过滤掉尖括号以及单、双引号就能干掉绝大部分的。下面我们来看看的HTML标签过滤代码,如下所示:

($html)

if(!(''))

("/


限时特惠:
本站持续每日更新海量各大内部创业课程,一年会员仅需要98元,全站资源免费下载
点击查看详情

站长微信:Jiucxh

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注