色色一区二区三区,一本大道道久久九九AV综合,国产香蕉97碰碰视频va碰碰看,综合亚洲国产2020

    <legend id="mljv4"><u id="mljv4"><blockquote id="mljv4"></blockquote></u></legend>

    <sub id="mljv4"><ol id="mljv4"><abbr id="mljv4"></abbr></ol></sub>
      <mark id="mljv4"></mark>

      您現(xiàn)在的位置是:教育

      代碼安全之參數(shù)安全過(guò)濾

      2018-09-12 09:38教育

      簡(jiǎn)介所有對(duì)Web應(yīng)用的攻擊都要傳入有害的參數(shù),因此代碼安全的基礎(chǔ)就是對(duì)傳入的參數(shù)進(jìn)行有效的過(guò)濾,比如像SQL注入漏洞,只要過(guò)濾到單引號(hào),就能防御住大部分的string類(lèi)型的SQL注入,只要過(guò)濾掉尖括號(hào)和單雙引號(hào)也能過(guò)濾掉不少XSS漏洞,這種簡(jiǎn)單的過(guò)濾跟完全不過(guò)...

      所有對(duì)Web應(yīng)用的攻擊都要傳入有害的參數(shù),因此代碼安全的基礎(chǔ)就是對(duì)傳入的參數(shù)進(jìn)行有效的過(guò)濾,比如像SQL注入漏洞,只要過(guò)濾到單引號(hào),就能防御住大部分的string類(lèi)型的SQL注入,只要過(guò)濾掉尖括號(hào)和單雙引號(hào)也能過(guò)濾掉不少XSS漏洞,這種簡(jiǎn)單的過(guò)濾跟完全不過(guò)濾帶來(lái)的效果是天壤之別,我們做的就是要細(xì)化這些過(guò)濾規(guī)則,通過(guò)橫向擴(kuò)展防御策略來(lái)攔截更多的攻擊,不少第三方提供了這樣的過(guò)濾函數(shù)和類(lèi),我們可以直接引用,另外PHP自身提供了不少過(guò)濾的函數(shù),好好使用這些內(nèi)置的函數(shù)也能達(dá)到非常好的效果。

       

      一、第三方過(guò)濾函數(shù)與類(lèi)

       

      在一些中小型的Web應(yīng)用程序中,由于大多數(shù)開(kāi)發(fā)者是不怎么懂安全的,所以都會(huì)選擇一些第三方的過(guò)濾函數(shù)或者類(lèi),直接拿過(guò)去套著用,并不知道效果到底怎么樣。在PHP安全過(guò)濾的類(lèi)里面,比較出名的有出自80sec團(tuán)隊(duì)給出的一個(gè)SQL注入過(guò)濾的類(lèi),在國(guó)內(nèi)大大小小的程序像discuz、dedecms、phpmywind等都使用過(guò)。

      目前大多數(shù)應(yīng)用都有一個(gè)參數(shù)過(guò)濾的統(tǒng)一入口,類(lèi)似于dedecms的代碼,如下所示:

       

      foreach(Array('_GET','_POST','_COOKIE')as $_request)

      {

      foreach($$_request as $_k => $_v)

      {

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

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

      }

      }

       

      跟進(jìn)_RunMagicQuotes()函數(shù)之后的代碼如下:

       

      function _RunMagicQuotes(&$svar)

      {

      if(!get_magic_quotes_gpc())

      {

      if(is_array($svar))

      {

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

      }

      else

      {

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

      {

      exit('Request var not allow!');

      }

      $svar = addslashes($svar);

      }

      }

      return $svar;

      }

       

      而這里僅僅是使用addslashes()函數(shù)過(guò)濾,確實(shí)能防御住一部分漏洞,但是對(duì)特定的場(chǎng)景和漏洞就不那么好使了。所以除了總?cè)肟,在具體的功能點(diǎn)也需要進(jìn)行一些過(guò)濾。

       

      (一)discuz SQL安全過(guò)濾類(lèi)分析

       

      discuz全稱(chēng)Crossday Discuz!Board,是一套開(kāi)源通用的社區(qū)論壇軟件系統(tǒng),使用PHP+MySQL開(kāi)發(fā),由于用戶(hù)量巨大,discuz一直是眾多安全愛(ài)好者重點(diǎn)研究的對(duì)象,所以也被公布過(guò)不少的安全漏洞。經(jīng)過(guò)數(shù)年的沉淀,如今的discuz主程序在代碼安全方面已經(jīng)做得比較成熟。

       

      discuz在專(zhuān)門(mén)有一個(gè)SQL注入過(guò)濾類(lèi)來(lái)過(guò)濾SQL注入請(qǐng)求,不過(guò)也出現(xiàn)了多次繞過(guò)的情況,下面我們來(lái)分析它的這個(gè)SQL注入過(guò)濾的類(lèi)。

       

      首先我們先看到discuz的配置文件/config/config_global.php中的“CONFIG SECURITY”部分內(nèi)容,如下:

       

      // -------------------------  CONFIG SECURITY  -------------------------- //

      $_config['security']['authkey'] = '3ca530i1uCe7lRke';

      $_config['security']['urlxssdefend'] = 1;

      $_config['security']['attackevasive'] = '0';

      $_config['security']['querysafe']['status'] = 1;

      //是否開(kāi)啟SQL注入防御//

       

      以下是過(guò)濾規(guī)則

       

      $_config['security']['querysafe']['dfunction']['0'] = 'load_file';

      $_config['security']['querysafe']['dfunction']['1'] = 'hex';

      $_config['security']['querysafe']['dfunction']['2'] = 'substring';

      $_config['security']['querysafe']['dfunction']['3'] = 'if';

      $_config['security']['querysafe']['dfunction']['4'] = 'ord';

      $_config['security']['querysafe']['dfunction']['5'] = 'char';

      $_config['security']['querysafe']['daction']['0'] = '@';

      $_config['security']['querysafe']['daction']['1'] = 'intooutfile';

      $_config['security']['querysafe']['daction']['2'] = 'intodumpfile';

      $_config['security']['querysafe']['daction']['3'] = 'unionselect';

      $_config['security']['querysafe']['daction']['4'] = '(select';

      $_config['security']['querysafe']['daction']['5'] = 'unionall';

      $_config['security']['querysafe']['daction']['6'] = 'uniondistinct';

      $_config['security']['querysafe']['dnote']['0'] = '/*';

      $_config['security']['querysafe']['dnote']['1'] = '*/';

      $_config['security']['querysafe']['dnote']['2'] = '#';

      $_config['security']['querysafe']['dnote']['3'] = '--';

      $_config['security']['querysafe']['dnote']['4'] = '"';

      $_config['security']['querysafe']['dlikehex'] = 1;

      $_config['security']['querysafe']['afullnote'] = '0';

       

      我們可以看到discuz配置文件中可以設(shè)置是否開(kāi)啟SQL注入防御,這個(gè)選項(xiàng)默認(rèn)開(kāi)啟,一般不會(huì)有管理員去關(guān)閉,再往下的內(nèi)容:

       

      $_config['security']['querysafe']['daction']

       

      以及

       

      $_config['security']['querysafe']['dnote']

       

      都是SQL注入過(guò)濾類(lèi)的過(guò)濾規(guī)則,規(guī)則里包含了常見(jiàn)的注入關(guān)鍵字。

       

      Discuz執(zhí)行SQL語(yǔ)句之前會(huì)調(diào)用\source\class\discuz\discuz_database.php文件discuz_database_safecheck類(lèi)下面的checkquery($sql)函數(shù)進(jìn)行過(guò)濾,我們來(lái)跟進(jìn)這個(gè)函數(shù)看看,代碼如下:

       

      public static function checkquery($sql)

      {

      if(self::$config === null)

      {

      self::$config = getglobal('config/security/querysafe');

      }

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

      {

      $check = 1;

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

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

      {

      $check = self::_do_query_safe($sql);

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

      {

      $check = -1;

      }

      if($check < 1)

      {

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

      }

      }

      return true;

      }

       

      從代碼中可以看到,程序首先加載配置文件中的config/security/querysafe,根據(jù)$config['status']判斷SQL注入防御是否開(kāi)啟,再到$check=self::_do_query_safe($sql);可以看到該函數(shù)又調(diào)用了同類(lèi)下的_do_query_safe()函數(shù)對(duì)SQL語(yǔ)句進(jìn)行過(guò)濾,我們繼續(xù)跟進(jìn)_do_query_safe()函數(shù),代碼如下:

       

      private static function _do_query_safe($sql)

      {

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

      $mark = $clean = '';

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

      {

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

      else 

      {

      $len = strlen($sql);

      $mark = $clean = '';

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

      {

      $str = $sql[$i];

      switch($str)

      {

      case '`':if(!$mark)

      {

      $mark = '`';

      $clean .= $str;

      elseif($mark == '`')

      {

      $mark = '';

      }

      break;

      case '\'':

      if(!$mark)

      {

      $mark = '\'';

      $clean .= $str;

      elseif($mark == '\'')

      {

      $mark = '';

      }

      break;

      case '/':

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

      {

      $mark = '/*';

      $clean .= $mark;

      $i++;

      elseif($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)&& substr($sql,$i,3)== '-- ')

      {

      $mark = '-- ';

      $clean .= $mark;

      }

      break;

      default:

      break;

      }

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

      }

      }

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

      {

      return '-3';

      }

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

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

      {

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

      }

      if(is_array(self::$config['dfunction']))

      {

      foreach(self::$config['dfunction'] as $fun)

      {

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

      return '-1';

      }

      }

      if(is_array(self::$config['daction']))

      {

      foreach(self::$config['daction'] as $action)

      {

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

      return '-3';

      }

      }

      if(self::$config['dlikehex'] && strpos($clean,'like0x'))

      {

      return '-2';

      }

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

      {

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

      {

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

      return '-4';

      }

      }

      return 1;

      }

       

      從如上代碼我們可以看到,該函數(shù)首先使用:

       

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

       

      將SQL語(yǔ)句中的\\、\'、\"以及''替換為空,緊接著是一個(gè)if else判斷邏輯來(lái)選擇過(guò)濾的方式:

       

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

      {

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

      else

       {

       

      這段代碼表示當(dāng)SQL語(yǔ)句里存在'/'、#'、'--'、'@'、'`'這些字符時(shí),則直接調(diào)用preg_replace()函數(shù)將單引號(hào)(')中間的內(nèi)容替換為空,這里之前存在一個(gè)繞過(guò),只要把SQL注入的語(yǔ)句放到單引號(hào)中間,則會(huì)被替換為空,進(jìn)行下面再判斷的時(shí)候已經(jīng)檢測(cè)不到SQL注入的關(guān)鍵字,導(dǎo)致繞過(guò)的出現(xiàn),在MySQL中使用@`'`代表null,SQL語(yǔ)句可以正常執(zhí)行。

       

      else條件中是對(duì)整段SQL語(yǔ)句進(jìn)行逐個(gè)字符進(jìn)行判斷,比如:

       

      case '/':

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

      {

      $mark = '/*';

      $clean .= $mark;

      $i++;

      }

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

      {

      $mark = '';

      $clean .= '*';

      }

      break;

       

      這段代碼的邏輯是,當(dāng)檢查到SQL語(yǔ)句中存在斜杠(/)時(shí),則去判斷下一個(gè)字符是不是星號(hào)(*),如果是星號(hào)(*)就把這兩個(gè)字符拼接起來(lái),即/*,然后繼續(xù)判斷下一個(gè)字符是不是星號(hào)(*),如果是星號(hào)則再繼續(xù)拼接起來(lái),得到/**,最后在如下代碼中判斷是否存在原來(lái)攔截規(guī)則里面定義的字符,如果存在則攔截SQL語(yǔ)句執(zhí)行:

       

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

      {

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

      {

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

      return '-4';

      }

      }

       

      國(guó)內(nèi)知名的多款cms應(yīng)用如dedecms等,都有使用類(lèi)似這個(gè)過(guò)濾類(lèi),另外由于應(yīng)用的基礎(chǔ)架構(gòu)不一樣,這個(gè)過(guò)濾類(lèi)應(yīng)用起來(lái)的實(shí)際效果也各不太一樣,discuz目前做得相對(duì)較好。

       

      (二)discuz XSS標(biāo)簽過(guò)濾函數(shù)分析

       

      目前大多數(shù)XSS過(guò)濾都是基于黑名單的形式,編程語(yǔ)言和編碼結(jié)合起來(lái)千變?nèi)f化,基于黑名單的過(guò)濾總給人不靠譜的感覺(jué),事實(shí)確實(shí)是這樣,目前好像還沒(méi)有看到基于黑名單過(guò)濾的規(guī)則一直沒(méi)有被繞過(guò),其實(shí)在XSS的防御上,只要過(guò)濾掉尖括號(hào)以及單、雙引號(hào)就能干掉絕大部分的payload。下面我們來(lái)看看discuz的HTML標(biāo)簽過(guò)濾代碼,如下所示:

       

      function checkhtml($html)

      {

      if(!checkperm('allowhtml'))

      {

      preg_match_all("/\<([^\<]+)\>/is",$html,$ms);

      $searchs[] = '<';

      $replaces[] = '&lt;';

      $searchs[] = '>';

      $replaces[] = '&gt;';

      if($ms[1])

      {

      $allowtags = 'img|a|font|div|table|tbody|caption|tr|td|th|br|p|b|strong|i|u|em|span|ol|ul|li|blockquote|object|param';

      $ms[1] = array_unique($ms[1]);

      foreach($ms[1] as $value)

      {

      $searchs[] = "&lt;".$value."&gt;";

      $value = str_replace('&','_uch_tmp_str_',$value);

      $value = dhtmlspecialchars($value);

      $value = str_replace('_uch_tmp_str_','&',$value);

      $value = str_replace(array('\\','/*'),array('.','/.'),$value);

      $skipkeys = array('onabort','onactivate','onafterprint','onafterupdate','onbeforeactivate','onbeforecopy','onbeforecut','onbeforedeactivate','onbeforeeditfocus','onbeforepaste','onbeforeprint','onbeforeunload','onbeforeupdate','onblur','onbounce','oncellchange','onchange','onclick','oncontextmenu','oncontrolselect','oncopy','oncut','ondataavailable','ondatasetchanged','ondatasetcomplete','ondblclick','ondeactivate','ondrag','ondragend','ondragenter','ondragleave','ondragover','ondragstart','ondrop','onerror','onerrorupdate','onfilterchange','onfinish','onfocus','onfocusin','onfocusout','onhelp','onkeydown','onkeypress','onkeyup','onlayoutcomplete','onload','onlosecapture','onmousedown','onmouseenter','onmouseleave','onmousemove','onmouseout','onmouseover','onmouseup','onmousewheel','onmove','onmoveend','onmovestart','onpaste','onpropertychange','onreadystatechange','onreset','onresize','onresizeend','onresizestart','onrowenter','onrowexit','onrowsdelete','onrowsinserted','onscroll','onselect','onselectionchange','onselectstart','onstart','onstop','onsubmit','onunload','javascript','script','eval','behaviour','expression','style','class');

      $skipstr = implode('|',$skipkeys);

      $value = preg_replace(array("/($skipstr)/i"),'.',$value);

      if(!preg_match("/^[\/|\s]?($allowtags)(\s+|$)/is",$value))

      {

      $value = '';

      }

      $replaces[] = empty($value)?'':"<".str_replace('&quot;','"',$value).">";

      }

      }

      $html = str_replace($searchs,$replaces,$html);

      }

      return $html;

      }

       

      從代碼中可以看到,這里首先定義了一條正則取出來(lái)尖括號(hào)中間的內(nèi)容:

       

      preg_match_all("/\<([^\<]+)\>/is",$html,$ms);

       

      然后在if($ms[1])這個(gè)if條件里對(duì)這些標(biāo)簽中的關(guān)鍵字進(jìn)行篩選,$skipkeys變量定義了很多on事件的敏感字符,如下代碼中可以看到,最后拼接正則將這些字符串替換掉:

       

      $skipstr = implode('|',$skipkeys);

      value = preg_replace(array("/($skipstr)/i"),'.',$value);

       

      二、內(nèi)置過(guò)濾函數(shù)

       

      PHP本身內(nèi)置了很多參數(shù)過(guò)濾的函數(shù),以方便開(kāi)發(fā)者簡(jiǎn)單有效且統(tǒng)一地進(jìn)行安全防護(hù),而這些函數(shù)可以分為多種類(lèi)型,如SQL注入過(guò)濾函數(shù)、XSS過(guò)濾函數(shù)、命令執(zhí)行過(guò)濾函數(shù)、代碼執(zhí)行過(guò)濾函數(shù),等等,下面我們來(lái)看看這些函數(shù)的用法。

       

      1、SQL注入過(guò)濾函數(shù)

       

      SQL注入過(guò)濾函數(shù)有addslashes()、mysql_real_escape_string()以及mysql_escape_string(),它們的作用都是給字符串添加反斜杠(\)來(lái)轉(zhuǎn)義掉單引號(hào)(')、雙引號(hào)(")、反斜線(\)以及空字符NULL。addslashes()和mysql_escape_string()函數(shù)都是直接在敏感字符串前加反斜杠,這里可能會(huì)存在繞過(guò)寬字節(jié)注入繞過(guò)的問(wèn)題,而mysql_real_escape_string()函數(shù)會(huì)考慮當(dāng)前連接數(shù)據(jù)庫(kù)的字符集編碼,安全性更好,推薦使用。

       

      2、XSS過(guò)濾函數(shù)

       

      XSS過(guò)濾函數(shù)有htmlspecialchars()和strip_tags(),這兩個(gè)函數(shù)的功能大不一樣,htmlspecialchars()函數(shù)的作用是將字符串中的特殊字符轉(zhuǎn)換成HTML實(shí)體編碼,如&轉(zhuǎn)換成&amp;,"轉(zhuǎn)換成&quot;,'轉(zhuǎn)換成&#039;,<轉(zhuǎn)換成&lt;,>轉(zhuǎn)換成&gt;這個(gè)函數(shù)簡(jiǎn)單粗暴但是卻非常有效果,已經(jīng)能干掉大多數(shù)的XSS攻擊。

       

      而strip_tags()函數(shù)則是用來(lái)去掉HTML及PHP標(biāo)記,比如給這個(gè)函數(shù)傳入“<h1>xxxxx</h1>”,經(jīng)過(guò)它處理后返回的字符串為xxxxx。

       

      3、命令執(zhí)行過(guò)濾函數(shù)

       

      通常我們進(jìn)行系統(tǒng)命令注入的時(shí)候會(huì)使用到||以及&等字符,PHP為了防止系統(tǒng)命令注入的漏洞,提供了escapeshellcmd()和escapeshellarg()兩個(gè)函數(shù)對(duì)參數(shù)進(jìn)行過(guò)濾,escapeshellcmd()函數(shù)過(guò)濾的字符為'&'、';'、'`'、'|'、'*'、'?'、'~'、'<'、'>'、'^'、'('、')'、'['、']'、'{'、'}'、'$'、'\'、'\x0A'、'\xFF'、’%’以及單雙引號(hào),Windows下過(guò)濾方式則是在這些字符前面加了一個(gè)^符號(hào),而在Linux下則是在這些字符前面加了反斜杠(\)。escapeshellarg()函數(shù)過(guò)濾方式比較簡(jiǎn)單,給所有參數(shù)加上一對(duì)雙引號(hào),強(qiáng)制為字符串。

      Tags:代碼,安全,參數(shù),過(guò)濾,所有,Web,用的,攻擊,都要,傳入