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