久久久久久久视色,久久电影免费精品,中文亚洲欧美乱码在线观看,在线免费播放AV片

<center id="vfaef"><input id="vfaef"><table id="vfaef"></table></input></center>

    <p id="vfaef"><kbd id="vfaef"></kbd></p>

    
    
    <pre id="vfaef"><u id="vfaef"></u></pre>

      <thead id="vfaef"><input id="vfaef"></input></thead>

    1. 站長(zhǎng)資訊網(wǎng)
      最全最豐富的資訊網(wǎng)站

      PDO原理及正確使用方法

      PDO原理及正確使用方法

      前言

      隨著數(shù)據(jù)庫(kù)參數(shù)化查詢的方式越來(lái)越普遍,SQL注入漏洞較之于以前也大大減少,而PDO作為php中最典型的預(yù)編譯查詢方式,使用越來(lái)越廣泛。

      眾所周知,PDO是php中防止SQL注入最好的方式,但并不是100%杜絕SQL注入的方式,關(guān)鍵還要看如何使用。

      之前在一篇文章中了解到PDO場(chǎng)景下參數(shù)可控導(dǎo)致的多句執(zhí)行等問題(https://xz.aliyun.com/t/3950)于是對(duì)PDO場(chǎng)景下的SQL注入又進(jìn)行了一些探究。

      PDO查詢語(yǔ)句可控存在的安全問題:

      首先在本地新建一個(gè)庫(kù)和表,隨便寫點(diǎn)東西。

      PDO原理及正確使用方法

      然后寫一個(gè)test.php,用PDO進(jìn)行簡(jiǎn)單的查詢:

      <?php  try{   $db = new PDO('mysql:host=localhost;dbname=pdotest','root',''); }  catch(Exception $e) {  echo $e->getMessage(); }if(isset($_GET['id'])) {   $id = $_GET['id']; }else{   $id=1; } $query = "select balabala from table1 where 1=?";echo "id:".$id."</br>"; $row = $db->prepare($query); $row->bindParam(1,$id); $row->execute(); $result = $row->fetch(PDO::FETCH_ASSOC);if($result) {  echo "結(jié)果為:";   print_r($result);  echo "</br>"; }

      將輸入的內(nèi)容和得到的結(jié)果打印在頁(yè)面上:

      PDO原理及正確使用方法

      PDO與安全問題相關(guān)的主要的設(shè)置有下面三個(gè):

      PDO::ATTR_EMULATE_PREPARES PDO::ATTR_ERRMODE PDO::MYSQL_ATTR_MULTI_STATEMENTS

      分別與模擬預(yù)編譯、報(bào)錯(cuò)和多句執(zhí)行有關(guān)。

      PDO默認(rèn)是允許多句執(zhí)行和模擬預(yù)編譯的,在之前的很多文章中已經(jīng)寫到,在參數(shù)可控的情況下,會(huì)導(dǎo)致堆疊注入。

      例如我們把查詢語(yǔ)句改成:

      $query = "select balabala from table1 where 1={$id}"; $row = $db->query($query);

      則在$db->query()這一步執(zhí)行之前,我們便可以對(duì)$query進(jìn)行非法操作,那PDO相當(dāng)于沒用:

      PDO原理及正確使用方法

      PDO默認(rèn)設(shè)置存在的安全隱患:

      如果我們?cè)诓樵冋Z(yǔ)句中沒有可控的參數(shù),并把輸入的參數(shù)按照prepare->bindParam->execute的方式去寫就一定沒有問題了嗎?

      我們按如下語(yǔ)句進(jìn)行查詢:

      $query = "select balabala from table1 where 1=?"; $row = $db->prepare($query); $row->bindParam(1,$_GET[‘id’]); $row->execute();

      我們?cè)赨RL中隨便輸入一個(gè)參數(shù):?id=asdasd,然后通過設(shè)置SET GLOBAL GENERAL_LOG=ON,從.log里實(shí)時(shí)監(jiān)控,看看sql語(yǔ)句到底執(zhí)行了什么:

      PDO原理及正確使用方法

      我們發(fā)現(xiàn)模擬預(yù)編譯的請(qǐng)求發(fā)送方式和以往的mysqli并沒有什么區(qū)別,但我們注意到,在原有的查詢語(yǔ)句中對(duì)參數(shù)并沒有用單引號(hào)包裹,而在此卻用單引號(hào)進(jìn)行了包裹,于是我們可以嘗試輸入一些特殊字符,比如單引號(hào):

      PDO原理及正確使用方法

      發(fā)現(xiàn)單引號(hào)被轉(zhuǎn)義了,這時(shí)我們不由得想到如果設(shè)置了gbk編碼會(huì)怎么樣:

      PDO原理及正確使用方法

      我們會(huì)發(fā)現(xiàn)select * from table1成功執(zhí)行了,盡管PDO只會(huì)返回一個(gè)結(jié)果,但是它的的確確執(zhí)行了。

      也就是說(shuō),即使查詢語(yǔ)句里沒有可控參數(shù),只有?或者:id這類被綁定的參數(shù),依然可以進(jìn)行堆疊注入。

      那如果把多句執(zhí)行關(guān)掉呢?

      我們把PDO::MYSQL_ATTR_MULTI_STATEMENTS設(shè)為false,重復(fù)上述操作:

      PDO原理及正確使用方法

      發(fā)現(xiàn)已經(jīng)行不通了。

      PDO原理及正確使用方法

      實(shí)際也只執(zhí)行了設(shè)置gbk這一條語(yǔ)句

      但是這樣就結(jié)束了嗎?

      為什么不試試union注入等其他方式呢?

      PDO原理及正確使用方法

      經(jīng)過嘗試,發(fā)現(xiàn)union注入也是可以的!根本不需要進(jìn)行多句執(zhí)行!

      實(shí)際上,在模擬預(yù)編譯的情況下,PDO對(duì)于SQL注入的防范(PDO::queto()),無(wú)非就是將數(shù)字型的注入轉(zhuǎn)變?yōu)樽址偷淖⑷?,又用類似mysql_real_escape_string()的方法將單引號(hào)、雙引號(hào)、反斜杠等字符進(jìn)行了轉(zhuǎn)義。

      這種防范方法在GBK編碼的情況下便可用寬字節(jié)進(jìn)行繞過,而在非GBK編碼的情況下,若存在二次注入的情況,是否能利用呢?

      答案是否定的。

      二次注入是由于對(duì)添加進(jìn)數(shù)據(jù)庫(kù)中的數(shù)據(jù)沒有再次處理和轉(zhuǎn)義而導(dǎo)致的,而預(yù)編譯對(duì)每次查詢都進(jìn)行轉(zhuǎn)義,則不存在二次注入的情況。

      上述安全隱患,是由于未正確設(shè)置PDO造成的,在PDO的默認(rèn)設(shè)置中,PDO::ATTR_EMULATE_PREPARES和PDO::MYSQL_ATTR_MULTI_STATEMENTS都是true,意味著模擬預(yù)編譯和多句執(zhí)行是默認(rèn)開啟的。

      而在非模擬預(yù)編譯的情況下,若語(yǔ)句中沒有可控參數(shù),是否還能這樣做呢?

      答案是否定的。

      我們將PDO::ATTR_EMULATE_PREPARES設(shè)為false,來(lái)看看sql語(yǔ)句到底執(zhí)行了什么:

      PDO原理及正確使用方法

      它對(duì)每一句sql語(yǔ)句都進(jìn)行了預(yù)編譯和執(zhí)行兩個(gè)操作,在執(zhí)行select balabala from table1 where 1=?這句時(shí),如果是GBK編碼,那么它將會(huì)把?綁定的參數(shù)轉(zhuǎn)化成16進(jìn)制,這樣無(wú)論輸入什么樣的東西都無(wú)法再進(jìn)行注入了。

      如果不是GBK編碼,如上面所說(shuō),也不存在二次注入的情況,故可以避免SQL注入漏洞。

      相同原理的Prepare Statement方法

      PDO的原理,與Mysql中prepare語(yǔ)句是一樣的。上面PDO所執(zhí)行的SQL語(yǔ)句,用如下的方式可以等效替代:

      Set @x=0x31 Prepare a from “select balabala from table1 where 1=?” Execute a using @x

      我們可以手動(dòng)將輸入的參數(shù)設(shè)置為@x,并將其轉(zhuǎn)化為16進(jìn)制,隨后預(yù)編譯,再執(zhí)行

      也就是說(shuō),不用PDO也可以仿照其原理手動(dòng)設(shè)置預(yù)編譯:

      $db = new mysqli('localhost','root','','pdotest');if(isset($_GET['id'])) { 	$id = "0x".bin2hex($_GET['id']); }else{ 	$id=1; }echo "id:".$id."</br>"; $db->query("set names gbk"); $db->query("set @x={$id}"); $db->query("prepare a from 'select balabala from table1 where 1=?'"); $row = $db->query("execute a using @x"); $result = $row->fetch_assoc();if($result) {	echo "結(jié)果為:"; 	print_r($result);	echo "</br>"; }

      得到的結(jié)果和使用PDO是一樣的:

      PDO原理及正確使用方法

      這樣設(shè)置不用擔(dān)心沒有合理地設(shè)置PDO,或是用了GBK編碼等情況。

      Prepare Statement在SQL注入中的利用

      Prepare語(yǔ)句在防范SQL注入方面起到了非常大的作用,但是對(duì)于SQL注入攻擊卻也提供了新的手段。

      Prepare語(yǔ)句最大的特點(diǎn)就是它可以將16進(jìn)制串轉(zhuǎn)為語(yǔ)句字符串并執(zhí)行。如果我們發(fā)現(xiàn)了一個(gè)存在堆疊注入的場(chǎng)景,但過濾非常嚴(yán)格,便可以使用prepare語(yǔ)句進(jìn)行繞過。

      例如我們將createtable table2 like table1轉(zhuǎn)化成16進(jìn)制,然后執(zhí)行:

      PDO原理及正確使用方法

      我們發(fā)現(xiàn)數(shù)據(jù)庫(kù)中已經(jīng)多了一個(gè)表table2。則語(yǔ)句成功執(zhí)行了。

      總結(jié)

      對(duì)于此類問題的防范,主要有以下三個(gè)方面:

      1. 合理、安全地使用gbk編碼。即使采用PDO預(yù)編譯的方式,如若配置不當(dāng),依然可造成寬字節(jié)注入

      2. 使用PDO時(shí),一定要將模擬預(yù)編譯設(shè)為false

      3. 可采用使用Prepare Statement手動(dòng)預(yù)編譯,杜絕SQL注入

      相關(guān)文章教程推薦:網(wǎng)站安全教程

      贊(0)
      分享到: 更多 (0)
      網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)