一、 建立乙個安全抽象層
我們並不建議你手工地把前面介紹的技術應用於每乙個使用者輸入的例項中,而是強烈推薦你為此建立乙個抽象層。乙個簡單的抽象是把你的校驗方案加入到乙個函式中,並且針對使用者輸入的每一項呼叫這個函式。當然,我們還可以建立一種更複雜的更高一級的抽象-把乙個安全的查詢封裝到乙個類中,從而應用於整個應用程式。在網上已經存在許多這種現成的免費的類;在本篇中,我們正要討論其中的一些。
進行這種抽象至少存在三個優點(而且每乙個都會改進安全級別):
1. 本地化**。
2. 使查詢的構造更快且更為可靠-因為這可以把部分工作交由抽象**來實現。
3. 當基於安全特徵進行構建並且恰當使用時,這將會有效地防止我們前面所討論的各種各樣的注入式攻擊。
二、 改進現有的應用程式
如果你想改進乙個現有的應用程式,則使用乙個簡單的抽象層是最適當的。乙個能夠簡單地"清理"你所收集的任何使用者輸入內容的函式可能看起來如下所示:
function safe( $string )
【注意】我們已經構建了相應於值要求的單引號以及mysql_real_escape_string()函式。接下來,就可以使用這個函式來構造乙個$query變數,如下所示:
$variety = safe( $_post['variety'] );
$query = " select * from wines where variety=" . $variety;
現在,你的使用者試圖進行乙個注入式攻擊-通過輸入下列內容作為變數$variety的值:
lagrein' or 1=1;
注意,如果不進行上面的"清理",則最後的查詢將如下所示(這將導致無法預料的結果):
select * from wines where variety = 'lagrein' or 1=1;'
然而現在,既然使用者的輸入已經被清理,那麼查詢語句就成為下面這樣一種無危害的形式:
select * from wines where variety = 'lagrein/' or 1=1/;'
既然資料庫中不存在與指定的值相應的variety域(這正是惡意使用者所輸入的內容-lagrein' or 1=1;),那麼,這個查詢將不能返回任何結果,並且注入將會失敗。
三、 保護乙個新的應用程式
如果你正在建立乙個新的應用程式,那麼,你可以從頭開始建立乙個安全抽象層。如今,php 5新改進的對於mysql的支援(這主要體現在新的mysqli擴充套件中)為這種安全特徵提供了強有力的支援(既有過程性的,也有物件導向特徵的)。你可以從站點http://php.net/mysqli上獲取有關mysqli的資訊。注意,只有當你使用--with-mysqli=path/to/mysql_config選項編譯php時,這種mysqli支援才可用。下面是該**的乙個過程性版本,用於保護乙個基於mysqli的查詢:
<?php
//檢索使用者的輸入
$animalname = $_post['animalname'];
//連線到資料庫
$connect = mysqli_connect( 'localhost', 'username', 'password', 'database' );
if ( !$connect ) exit( 'connection failed: ' . mysqli_connect_error() );
//建立乙個查詢語句源
$stmt = mysqli_prepare( $connect,"select intelligence from animals where name = ?" );
if ( $stmt ) else
//清除語句源
mysqli_stmt_close( $stmt );
}mysqli_close( $connect );
?> 該mysqli擴充套件提供了一組函式用於構造和執行查詢。而且,它也非常準確地提供了前面使用我們自己的safe()函式所實現的功能。
在上面的片斷中,首先收集使用者提交的輸入內容並建立資料庫連線。然後,使用mysqli_prepare()函式建立乙個查詢語句源-在此命名為$stmt以反映使用它的函式的名稱。這個函式使用了兩個引數:連線資源和乙個字串(每當你使用擴充套件插入乙個值時,"?"標記被插入到其中)。在本例中,你僅有乙個這樣的值-動物的名字。
注意,在乙個select語句中,放置"?"標記的唯一的有效位置是在值比較部分。這正是為什麼你不需要指定使用哪個變數的原因(除了在mysqli_stmt_bind_param()函式中之外)。在此,你還需要指定它的型別-在本例中,"s"代表字串。其它可能的型別有:"i"代表整數,"d"代表雙精度數(或浮點數),而"b"代表二進位制字串。
函式mysqli_stmt_execute(),mysqli_stmt_bind_result()和mysqli_stmt_fetch()負責執行查詢並檢索結果。如果存在檢索結果,則顯示它們;如果不存在結果,則顯示一條無害的訊息。最後,你需要關閉$stmt資源以及資料庫連線-從記憶體中對它們加以釋放。
假定乙個合法的使用者輸入了字串"lemming",那麼這個例程將(假定是資料庫中適當的資料)輸出訊息"a lemming has very low intelligence."。假定存在乙個嘗試性注入-例如"lemming' or 1=1;",那麼這個例程將列印(無害)訊息"sorry, no records found."。
此外,mysqli擴充套件還提供了乙個物件導向版本的相同的例程。下面,我們想說明這種版本的使用方法。
<?php
$animalname = $_post['animalname'];
$mysqli = new mysqli( 'localhost', 'username', 'password', 'database');
if ( !$mysqli ) exit( 'connection failed: ' . mysqli_connect_error() );
$stmt = $mysqli->prepare( "select intelligence
from animals where name = ?" );
if ( $stmt ) else
$stmt->close();
}$mysqli->close();
?> 實際上,這部分**是前面描述**的複製-它使用了一種物件導向的語法和組織方法,而不是嚴格的過程式**。
四、 更高階的抽象
如果你使用外部庫peardb,那麼,你可以對應用程式的安全保護模組進行全面的抽象。
另一方面,使用這個庫存在乙個突出的缺點:你只能受限於某些人的思想,而且**管理方面也新增了大量的工作。為此,在決定是否使用它們之前,你需要進行仔細地斟酌。如果你決定這樣做,那麼,你至少確保它們能夠真正幫助你"清理"你的使用者輸入的內容。
五、 測試你的注入式保護能力
正如我們在前面所討論的,確保你的指令碼安全的乙個重要的部分是對它們進行測試。為此,最好的辦法是你自己建立sql**注入測試。
在此,我們提供了乙個這種測試的示例。在本例中,我們測試對乙個select語句的注入式攻擊。
<?php
//被測試的保護函式
function safe( $string )
//連線到資料庫
/////試圖進行注入
///$exploit = "lemming' and 1=1;";
//進行清理
$safe = safe( $exploit );
$query = "select * from animals where name = $safe";
$result = mysql_query( $query );
//測試是否保護是足夠的
if ( $result && mysql_num_rows( $result ) == 1 )
else
?> 如果你想建立這樣的乙個測試集,並試驗基於不同的sql命令的各種不同的注入,那麼,你將會很快地探測出你的保護策略中的任何漏洞。一旦糾正這些問題,那麼,你就可以很有把握-你已經建立起真正的注入式攻擊保護機制。
六、 小結
在本系列文章一開始,我們通過乙個sql注入討論分析了對你的指令碼的特定威脅-由不恰當的使用者輸入所致。之後,我們描述了sql注入的工作原理並精確地分析了php是怎樣易於被注入的。然後,我們提供了乙個實際中的注入示例。之後,我們推薦一系列措施來使試圖的注入攻擊變為無害的-這將分別通過確保使所有提交的值以引號封閉,通過檢查使用者提交值的型別,以及通過過濾掉你的使用者輸入的潛在危險的字元等方法來實現的。最後,我們推薦,你最好對你的校驗例程進行抽象,並針對更改乙個現有應用程式提供了指令碼示例。然後,我們討論了第三方抽象方案的優缺點。
在PHP中全面阻止SQL注入式攻擊
在本系列文章中,我們將全面 如何在php開發環境中全面阻止sql注入式攻擊,並給出乙個具體的開發示例。一 引言 php是一種力量強大但相當容易學習的伺服器端指令碼語言,即使是經驗不多的程式設計師也能夠使用它來建立複雜的動態的web站點。然而,它在實現網際網路服務的秘密和安全方面卻常常存在許多困難。在...
在PHP中全面阻止SQL注入式攻擊之一
在本系列文章中,我們將全面 如何在php開發環境中全面阻止sql注入式攻擊,並給出乙個具體的開發示例。一 引言 php是一種力量強大但相當容易學習的伺服器端指令碼語言,即使是經驗不多的程式設計師也能夠使用它來建立複雜的動態的web站點。然而,它在實現網際網路服務的秘密和安全方面卻常常存在許多困難。在...
在PHP中全面阻止SQL注入式攻擊之一
在本系列文章中,我們將全面 如何在php開發環境中全面阻止sql注入式攻擊,並給出乙個具體的開發示例。一 引言 php是一種力量強大但相當容易學習的伺服器端指令碼語言,即使是經驗不多的程式設計師也能夠使用它來建立複雜的動態的web站點。然而,它在實現網際網路服務的秘密和安全方面卻常常存在許多困難。在...