天天看點

PHP中SQL注入與跨站攻擊的防範

SQL injection即SQL注入是我們每個WEB程式員都需要面對的問題,一個WEB應用假如沒有起碼的安全性,那麼其它的一切就可以免談了。注入問題在ASP上可謂是鬧得沸沸揚揚,當然還有不少PHP程式“遇難”。至于SQL injection的詳情,網上的文章很多,在此就不作贅述。追其罪惡之源,就是我們誤以為使用者送出的資料是可靠的。 

    無論你是否有足夠的PHP安全開發經驗,本文的目的就是用來幫助你建構更為安全的線上應用程式。針對不同的情況,我們可以使用下面的一種或幾種方法來對SQL注入的風險進行預防。 

    1、在書寫SQL語句時不要省略單引号,即使是整型字段也應該加上單引号。 

    首先,從技術上講,引号對于數字值來說是不需要使用的。但是,假如你不使用引号把例如書籍數量這樣的一個值括起來,并且假如你的使用者把一個空值輸入到你的表單中,那麼,你将會看到一個類似下面的查詢: 

SELECT * FROM books WHERE num = 

    當然,這個查詢從文法上講是無效的;但是,下面的文法卻是有效的: 

SELECT * FROM books WHERE num = '' 

    第二個查詢雖然也不會傳回任何結果,但是至少它不會傳回一個錯誤消息。 

    其次,單引号可以增加注入者的難度,第二句由于把變量放在一對單引号中,這樣使得我們所送出的變量都變成了字元串,即使包含了正确的SQL語句,也不會正常執行,而第一句不同,由于沒有把變量放進單引号中,那我們所送出的一切,隻要包含空格,那空格後的變量都會作為SQL語句執行,是以,我們要養成給SQL語句中變量加引号的習慣。 

    2、檢查使用者送出的值的類型,對接收到的整型參數使用intval()強制轉換成整形。 

    我們知道SQL注入的主要來源往往出在一個意料之外的表單送出或URL參數中,是以當你接受一個由使用者送出的參數時,你應該有相當的權利來确定你想取得什麼樣的輸入内容。在以前的學習中我們已經讨論過很多這樣或那樣的校驗問題。是以我們隻要簡單的總結當時我們讨論的要點即可比較輕易的檢查使用者送出資料的有效性。假如你期望得到的是一個數值,那麼你可以使用下面這些技術之一來確定你得到的參數的安全性。 

使用is_int()函數(或is_integer()或is_long())。 

使用gettype()函數。 

使用intval()函數。 

使用settype()函數。 

    我們通常把傳送過來的整型參數使用intval()函數強制轉換成整形,因為假如不這樣做,接收到的查詢子句很可能會附帶着其它一些我們并不願看到的語句,比如原本應該是“nid=17”可能會成為“nid=17 or 1=1”,這會使我們預計的SQL語句變成這樣: 

SELECT * FROM news WHERE nid=17 or 1=1 

這對于一個新聞表中的資訊可能不會造成什麼大的危害,但假如是在顯示某個使用者的資訊時呢? 

    此外,為了檢查使用者輸入内容的長度,你可以使用strlen()函數。為了檢查一個期望的時間或日期是否有效,你可以使用strtotime()函數。它似乎一定能夠確定一位使用者的送出參數中沒有包含分号字元(除非标點符号可以被合法地包括在内)。你可以借助于strpos()函數輕易地實作這一點,如下所示: 

if( strpos( $variety, ';' ) ) exit ( "$variety is an invalid value for variety!" ); 

正如我們在前面所提到的,隻要你仔細分析你的使用者輸入期望,那麼,你應該能夠很輕易地檢查出其中存在的許多問題。 

    3、使用mysql_real_escape_string()函數從查詢字元串中過濾掉危險字元 

    盡管有很多文章已經讨論過如何過濾掉危險字元的問題,但是在本文中還是讓我們再次簡單的強調并歸納一下這個問題: 

    不要使用magic_quotes_gpc指令或它的搭擋addslashes()函數,此函數在程式開發中應該是被限制使用的,在PHP的下一個版本PHP6中已經取消了對此函數的支援,并且此函數還要求使用額外的步驟stripslashes()函數。相比之下,mysql_real_escape_string()函數更為适合,受此函數影響的字元包括:\x00,\n,\r,\,',",\x1a。這二個函數的功能類似,但addslashes()函數無法轉換以十六進制形式送出的字元,另外需要注重的是,mysqli_real_escape_string()函數需要先建立資料庫連接配接,因為需要考慮到連接配接的目前字元集,通常防止資料庫被攻擊的使用方法如下: 

<?php 

function check_input($value) 

// 去除斜杠 

if (get_magic_quotes_gpc()) 

  { 

  $value = stripslashes($value); 

  } 

// 假如不是數字則加引号 

if (!is_numeric($value)) 

  $value = "'" . mysqli_real_escape_string($value) . "'"; 

return $value; 

?> 

    4、對使用者輸入的字元進行HTML編碼以防止跨站攻擊 

    對于資料庫防止SQL注入的問題,通過前面三點所述綜合的運用我們似乎全部解決,但假如使用者送出的内容中有一些不良的HTML标簽則可能會導緻頁面變形,嚴重的還可能會出現跨站攻擊之類的安全問題,是以對帶有HTML的内容增加過濾檢查是很有必要的。 

    例如一段接收使用者的輸入并顯示的功能代碼,一但惡意使用者輸入:<script type='text/javascript'>location.href='http://xxx.com';</script>這樣的一條資料,網頁在顯示該條資料時,使用者的浏覽器将會跳轉到惡意代碼指定的位址,這就是最簡單的跨站攻擊,我們試想一下,假如跳轉的位址是一個僞造原網站來騙取使用者密碼或銀行資訊的頁面,那麼會是什麼樣的後果? 

    對于這類攻擊行為,就需要我們在接收使用者送出的資料時在伺服器端進行過濾,我們可以編寫一個過濾函數用來查詢送出資料中有害字元并将之替換掉,還有一種較簡便的方式就把使用者所送出的内容中“<”,“>”,“&”等符号轉換成正确的HTML編碼,而函數htmlspecialchars()正是幹這個活的。 

htmlspecialchars() 

功能:将“'"&<>”五個字元轉換成HTML字元串。 

文法:string htmlspecialchars(string,quotestyle,character-set); 

參數:ENT_NOQUOTES,不對任何引号進行格式化;ENT_QUOTES,對單引号及雙引号進行格式化;預設為ENT_COMPAT,僅編碼雙引号。 

傳回值:字元串 

是以,使用者送出的資料經過格式化後為: 

<script type='text/javascript'>location.href='http://xxx.com';</script> 

這樣代碼就失去了原有的攻擊功能,可以基本預防腳本攻擊的潛在危險,假如不明白這之間的差別,可以測試下面這段代碼: 

$str="<a href='http://www.php3c.com'>PHP3C技術分享社群</a>"; 

echo $str; 

echo "<br>"; 

echo htmlspecialchars($str); 

    另外,轉換非凡字元為HTML字元串還可以使用函數htmlentities(),使用方法相同,它與htmlspecialchars在格式化帶有英文字元的html代碼的時候沒有什麼差別,但是htmlentities對中文字元也不放過,是以同樣的調用方法得出來的結果是由于沒有指定字元集而預設由 ISO-8859-1 代替,中文字元部分變為一堆亂碼,是以我們在使用的時候,需要指定參數character-set為我們頁面使用的字元集,例如'UTF-8'或'GB2312'。 

    SQL注入攻擊是針對伺服器端的資料庫實行的,而跨站腳本攻擊是把惡意javascript代碼在使用者的用戶端運作,但他們的相同之處在于攻擊者必須通過網際網路的輸入區域插入惡意的資料,是以我們隻要做好使用者送出資料的過濾以及合法性驗證就能從源頭上制止這二類攻擊,但這種過濾及驗證被很多程式員所忽視的,希望本文能能引起大家的重視。 

XSS(Cross Site Scripting),意為跨網站腳本攻擊,為了和樣式表css(Cascading Style Sheet)差別,縮寫為XSS

跨站腳本主要被攻擊者利用來讀取網站使用者的cookies或者其他個人資料,一旦攻擊者得到這些資料,那麼他就可以僞裝成此使用者來登入網站,獲得此使用者的權限。

跨站腳本攻擊的一般步驟:

1、攻擊者以某種方式發送xss的http連結給目标使用者

2、目标使用者登入此網站,在登陸期間打開了攻擊者發送的xss連結

3、網站執行了此xss攻擊腳本

4、目标使用者頁面跳轉到攻擊者的網站,攻擊者取得了目标使用者的資訊

5、攻擊者使用目标使用者的資訊登入網站,完成攻擊

PHP中SQL注入與跨站攻擊的防範

本文轉自ljianbing51CTO部落格,原文連結:http://blog.51cto.com/ljianbing/1603851 ,如需轉載請自行聯系原作者