2015年8月30日

PHP Data Objects (PDO) 簡易使用說明(2)-使用prepared指令避免sql injection


這篇文章主要是接續前一篇文章〈PHP Data Objects (PDO) 簡易使用說明-啟用PDO讀取資料庫資料〉,進一步說明如何透過prepare來防止可能的sql injection,另外也說明如何在PDO中使用where in ()的query方式。



如何達到sql injection


首先,一般的時候,執行以下指令,我可以獲得我資料庫裡的所有內容:

#查詢Query的結果
$sql = 'select * from pdo';
$statement = $connection->query($sql);

echo "<pre>";
print_r($statement->fetchALL(PDO::FETCH_ASSOC));
echo "</pre>";

結果像是這樣:



如果我想要限制,只要取出sn = 11的資料時,我可以把程式改成:
#查詢Query的結果
$sn = 11;
$sql = "select * from pdo where sn = $sn";
$statement = $connection->query($sql);

這時候便只會得到得到sn = 11的資料。

然後,若有心人士透過某些方法,把$sn = 11 改成$sn = 11 or 1,這時候他就可以撈出我們資料庫中所有的資料!

#查詢Query的結果
$sn =' 11 or 1';
$sql = "select * from pdo where sn = $sn";
$statement = $connection->query($sql);

prepared指令的使用


當我們使用$statement->query()的方式來擷取資料時,PDO會在內部先準備好一個指令,然後執行它。

當你使用的是$statement->prepared()時,你會先創造一個prepared的聲明(prepared statement),並且說明哪些是placeholder,會在之後的地方才放入。

當你之後執行$statement->execute()時,你再把屬於該placeholder的值放入,並且加以執行。

舉例來說:

我們可以先把我們sql改成如下,在變數前面加上冒號(:)表示它是placeholder,我們會在之後execute的時候再來填入它:

$sql = "select * from pdo where sn = :sn";

接著,把原本的query改成prepare

$statement = $connection->prepare($sql);

最後,在執行的地方,我們再把值放入placeholder之中:

$sn = 11;
$statement->execute(array(
    'sn' => $sn
));

這時候,我們一樣可以截取出sn = 11 的資料。

可是,這時候如果我們在把sn = 11 改成 sn = 11 or 1的話,將一樣只會出現sn = 11的資料,如此一來,便無法讓駭客成功獲得所有的資料。

$sn = '11 or 1';
$sql = "select * from pdo where sn = :sn";
$statement = $connection->prepare($sql);

$statement->execute(array(
    'sn' => $sn
));


echo "<pre>";
print_r($statement->fetchALL(PDO::FETCH_ASSOC));
echo "</pre>";


另一種prepared寫法則是用?取代placeholder像這樣:

$sn = '11';
$sql = "select * from pdo where sn = ?";
$statement = $connection->prepare($sql);
$statement->execute(array($sn));

echo "<pre>";
print_r($statement->fetchALL(PDO::FETCH_ASSOC));
echo "</pre>";

在PDO中使用where in 指令


在PDO中使用Where IN 指令也不困難,假設我想要獲取sn = 8,9,11,12資料,我可以先產生一個陣列:

$sn = array(8,9,11,12);


接著,看我想要取得幾個sn,我就輸入幾次問號,語法如下:

$placeholder = implode(',', array_fill(0, count($sn), '?'));

透過同樣的方法執行

$statement = $connection->prepare("SELECT * FROM pdo WHERE sn IN ($placeholder)");

$statement->execute($sn);

最後呼叫出結果來看:

echo "<pre>";
print_r($statement->fetchALL(PDO::FETCH_ASSOC));
echo "</pre>";

就可以看到,我們只抓取出sn = 8,9,11,12的資料。


結論


這兩篇文章提供了簡單使用PDO的方法,方便完全沒有經驗的人,可以逐漸上手PDO這個物件,然而,PDO的功能非常多,這裡只是帶到最基本的皮毛而已,若有需要繼續深入的人,可以透過網路或其他的參考資料,對PDO有更多的了解。

參考資料

0 意見:

張貼留言