一、 建立一個安全抽象層
我們並不建議你手工地把前面介紹的技術應用於每一個用戶輸入的實例中,而是強烈推薦你為此創建一個抽象層。一個簡單的抽象是把你的校驗方案加入到一個函數中,並且針對用戶輸入的每一項調用這個函數。當然,我們還可以創建一種更復雜的更高一級的抽象-把一個安全的查詢封裝到一個類中,從而應用於整個應用程序。在網上已經存在許多這種現成的免費的類;在本篇中,我們正要討論其中的一些。
進行這種抽象至少存在三個優點(而且每一個都會改進安全級別):
1. 本地化代碼。
2. 使查詢的構造更快且更為可靠-因為這可以把部分工作交由抽象代碼來實現。
3. 當基於安全特征進行構建並且恰當使用時,這將會有效地防止我們前面所討論的各種各樣的注入式攻擊。
二、 改進現有的應用程序
如果你想改進一個現有的應用程序,則使用一個簡單的抽象層是最適當的。一個能夠簡單地"清理"你所收集的任何用戶輸入內容的函數可能看起來如下所示:
function safe( $string ) {
return "'" . mysql_real_escape_string( $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;),那麼,這個查詢將不能返回任何結果,並且注入將會失敗。