1. 程式人生 > >PHP安全程式設計:防止SQL注入

PHP安全程式設計:防止SQL注入

SQL 注入是PHP應用中最常見的漏洞之一。事實上令人驚奇的是,開發者要同時犯兩個錯誤才會引發一個SQL注入漏洞,一個是沒有對輸入的資料進行過濾(過濾輸入),還有一個是沒有對傳送到資料庫的資料進行轉義(轉義輸出)。這兩個重要的步驟缺一不可,需要同時加以特別關注以減少程式錯誤。

對於攻擊者來說,進行SQL注入攻擊需要思考和試驗,對資料庫方案進行有根有據的推理非常有必要(當然假設攻擊者看不到你的源程式和資料庫方案),考慮以下簡單的登入表單:

  1. <form action="/login.php" method="POST">  
  2. <p>Username: <input type="text"
     name="username" /></p>  
  3. <p>Password: <input type="password" name="password" /></p>  
  4. <p><input type="submit" value="Log In" /></p>  
  5. </form>  


作為一個攻擊者,他會從推測驗證使用者名稱和密碼的查詢語句開始。通過檢視原始檔,他就能開始猜測你的習慣。

比如命名習慣。通常會假設你表單中的欄位名為與資料表中的欄位名相同。當然,確保它們不同未必是一個可靠的安全措施。

第一次猜測,一般會使用下面例子中的查詢:


  1. <?php  
  2. $password_hash = md5($_POST['password']);  
  3. $sql = "SELECT count(*)  
  4.       FROM   users  
  5.       WHERE  username = '{$_POST['username']}'
  6.       AND    password = '$password_hash'";  
  7. ?>  


使用使用者密碼的MD5值原來是一個通行的做法,但現在並不是特別安全了。最近的研究表明MD5演算法有缺陷,而且大量MD5資料庫降低了MD5反向破解的難度。請訪問http://md5.rednoize.com/ 檢視演示(原文如此,山東大學教授王小云的研究表明可以很快的找到MD5的“碰撞”,就是可以產生相同的MD5值的不同兩個檔案和字串。MD5是資訊摘要演算法,而不是加密演算法,反向破解也就無從談起了。不過根據這個成果,在上面的特例中,直接使用md5是危險的。)。


最好的保護方法是在密碼上附加一個你自己定義的字串,例如:

  1. <?php  
  2. $salt = 'SHIFLETT';  
  3. $password_hash = md5($salt . md5($_POST['password'] . $salt));  
  4. ?>  


當然,攻擊者未必在第一次就能猜中,他們常常還需要做一些試驗。有一個比較好的試驗方式是把單引號作為使用者名錄入,原因是這樣可能會暴露一些重要資訊。有很多開發人員在Mysql語句執行出錯時會呼叫函式mysql_error()來報告錯誤。見下面的例子:

  1. <?php  
  2. mysql_query($sqlorexit(mysql_error());  
  3. ?>  


雖然該方法在開發中十分有用,但它能向攻擊者暴露重要資訊。如果攻擊者把單引號做為使用者名稱,mypass做為密碼,查詢語句就會變成:

  1. <?php  
  2. $sql = "SELECT *  
  3.       FROM   users  
  4.       WHERE  username = '''  
  5.       AND    password = 'a029d0df84eb5549c641e04a9ef389e5'";  
  6. ?>  


當該語句傳送到MySQL後,系統就會顯示如下錯誤資訊:

  1. You have an error in your SQL syntax. Check the manual that corresponds to your  
  2. MySQL server version for the right syntax to use near 'WHERE username = ''' AND  
  3. password = 'a029d0df84eb55  


不費吹灰之力,攻擊者已經知道了兩個欄位名(username和password)以及他們出現在查詢中的順序。除此以外,攻擊者還知道了資料沒有正確進行過濾(程式沒有提示非法使用者名稱)和轉義(出現了資料庫錯誤),同時整個WHERE條件的格式也暴露了,這樣,攻擊者就可以嘗試操縱符合查詢的記錄了。

在這一點上,攻擊者有很多選擇。一是嘗試填入一個特殊的使用者名稱,以使查詢無論使用者名稱密碼是否符合,都能得到匹配:

  1. myuser' or 'foo' = 'foo' --  


假定將mypass作為密碼,整個查詢就會變成:

  1. <?php  
  2. $sql = "SELECT *  
  3.       FROM   users  
  4.       WHERE  username = 'myuser'or'foo' = 'foo' --  
  5.       AND    password = 'a029d0df84eb5549c641e04a9ef389e5'";  
  6. ?>  


由於中間插入了一個SQL註釋標記,所以查詢語句會在此中斷。這就允許了一個攻擊者在不知道任何合法使用者名稱和密碼的情況下登入。

如果知道合法的使用者名稱,攻擊者就可以該使用者(如chris)身份登入。只要chris是合法的使用者名稱,攻擊者就可以控制該帳號。原因是查詢變成了下面的樣子:

  1. <?php  
  2. $sql = "SELECT *  
  3.       FROM   users  
  4.       WHERE  username = 'chris' --  
  5.       AND    password = 'a029d0df84eb5549c641e04a9ef389e5'";  
  6. ?>  


幸運的是,SQL注入是很容易避免的。正如前面所提及的,你必須堅持過濾輸入和轉義輸出。

雖然兩個步驟都不能省略,但只要實現其中的一個就能消除大多數的SQL注入風險。如果你只是過濾輸入而沒有轉義輸出,你很可能會遇到資料庫錯誤(合法的資料也可能影響SQL查詢的正確格式),但這也不可靠,合法的資料還可能改變SQL語句的行為。另一方面,如果你轉義了輸出,而沒有過濾輸入,就能保證資料不會影響SQL語句的格式,同時也防止了多種常見SQL注入攻擊的方法。

當然,還是要堅持同時使用這兩個步驟。過濾輸入的方式完全取決於輸入資料的型別(見第一章的示例),但轉義用於向資料庫傳送的輸出資料只要使用同一個函式即可。對於MySQL使用者,可以使用函式mysql_real_escape_string( ):

  1. <?php  
  2. $clean = array();  
  3. $mysql = array();  
  4. $clean['last_name'] = "O'Reilly";  
  5. $mysql['last_name'] = mysql_real_escape_string($clean['last_name']);  
  6. $sql = "INSERT  
  7.       INTO   user (last_name)  
  8.       VALUES ('{$mysql['last_name']}')";  
  9. ?>  


儘量使用為你的資料庫設計的轉義函式。如果沒有,使用函式addslashes()是最終的比較好的方法。

當所有用於建立一個SQL語句的資料被正確過濾和轉義時,實際上也就避免了SQL注入的風險。如果你正在使用支援引數化查詢語句和佔位符的資料庫操作類(如PEAR::DB, PDO等),你就會多得到一層保護。見下面的使用PEAR::DB的例子:

  1. <?php  
  2. $sql = 'INSERT  
  3.       INTO   user (last_name)  
  4.       VALUES (?)';  
  5. $dbh->query($sqlarray($clean['last_name']));  
  6. ?>  


由於在上例中資料不能直接影響查詢語句的格式,SQL注入的風險就降低了。PEAR::DB會自動根據你的資料庫的要求進行轉義,所以你只需要過濾輸出即可。

如果你正在使用引數化查詢語句,輸入的內容就只會作為資料來處理。這樣就沒有必要進行轉義了,儘管你可能認為這是必要的一步(如果你希望堅持轉義輸出習慣的話)。實際上,這時是否轉義基本上不會產生影響,因為這時沒有特殊字元需要轉換。在防止SQL注入這一點上,引數化查詢語句為你的程式提供了強大的保護。

注:關於SQL注入,不得不說的是現在大多虛擬主機都會把magic_quotes_gpc選項開啟,在這種情況下所有的客戶端GET和POST的資料都會自動進行addslashes處理,所以此時對字串值的SQL注入是不可行的,但要防止對數字值的SQL注入,如用intval()等函式進行處理。但如果你編寫的是通用軟體,則需要讀取伺服器的magic_quotes_gpc後進行相應處理。

相關推薦

PHP安全程式設計防止SQL注入

SQL 注入是PHP應用中最常見的漏洞之一。事實上令人驚奇的是,開發者要同時犯兩個錯誤才會引發一個SQL注入漏洞,一個是沒有對輸入的資料進行過濾(過濾輸入),還有一個是沒有對傳送到資料庫的資料進行轉義(轉義輸出)。這兩個重要的步驟缺一不可,需要同時加以特別關注以減少程式錯誤

PHP安全程式設計session劫持的防禦session 資料暴露

GET / HTTP/1.1 Host: example.org User-Agent: Firefox/1.0 Accept: text/html, image/png, image/jpeg, image/gif, */* Cookie: PHPSESSID=1234你應該意識到請求的一致性,並把不一致的

淺析php過濾html字串,防止SQL注入的方法

本篇文章是對php中過濾html字串,防止SQL注入的方法進行了詳細的分析介紹,需要的朋友參考下   批量過濾post,get敏感資料 複製程式碼 程式碼如下: $_GET = stripslashes_array($_GET); $_POST = st

PHP安全程式設計session劫持的防禦

session 資料暴露 會話資料常會包含一些個人資訊和其它敏感資料。基於這個原因,會話資料的暴露是被普遍關心的問題。一般來說,暴露的範圍不會很大,因為會話資料是儲存在伺服器環境中的,而不是在資料庫或檔案系統中。因此,會話資料自然不會公開暴露。使用SSL是一種特別有效的手段

PHP中該怎樣防止SQL注入

問題描述 如果使用者輸入的資料在未經處理的情況下插入到一個SQL查詢語句中,那麼應用將很有可能遭受到SQL注入的攻擊,正如下面的例子: $unsafe_valiable = $_POST['user_input']; mysql_query("INSERT

PHP安全程式設計不要暴露資料庫訪問許可權

資料庫使用中需要關注的主要問題之一是訪問許可權即使用者名稱及密碼的暴露。在程式設計中為了方便,一般都會用一個db.inc檔案儲存,如: <?php   $db_user = 'myuser';   $db_pass = 'mypass';   $db_host =

PHP防止SQL注入的方法

【一、在伺服器端配置】        安全,PHP程式碼編寫是一方面,PHP的配置更是非常關鍵。 我們php手手工安裝的,php的預設配置檔案在 /usr/local/apache2/conf/php.ini,我們最主要

php對前臺提交的表單資料做安全處理(防SQL注入和XSS攻擊等)

/** * 防sql注入字串轉義 * @param $content 要轉義內容 * @return array|string */ public static function escapeString($content) { $pa

如何在PHP防止SQL注入

  1: 使用PDO物件(對於任何資料庫驅動都好用)2: addslashes用於單位元組字串的處理,3: 多位元組字元用mysql_real_escape_string吧。 另外對於php手冊中get_magic_quotes_gpc的舉例: if (!get_magic_quote

PHP實現防止SQL注入的2種方法

PHP簡單實現防止SQL注入的方法,結合例項形式分析了PHP防止SQL注入的常用操作技巧與注意事項,PHP原始碼備有詳盡註釋便於理解,需要的朋友可以參考下!   方法一:execute代入引數 $var_Value) { //獲取POST陣列最大值 $num = $nu

php操作mysql防止sql注入(合集)

本文將從sql注入風險說起,並且比較addslashes、mysql_escape_string、mysql_real_escape_string、mysqli和pdo的預處理的區別。 當一個變數從表單傳入到php,需要查詢mysql的話,需要進行處理。 舉例: $unsafe_variable

PHP使用PDO簡單實現防止SQL注入的方法

方法一:execute代入引數  <?php if(count($_POST)!= 0) { $host = 'aaa'; $database = 'bbb'; $username = 'ccc'; $password = '***'; $num

python Web安全防止SQL注入

伴隨著Web2.0、社交網路、微博等一系列新型網際網路產品的興起,基於Web環境的網際網路應用越來越廣泛,Web攻擊的手段也越來越多樣,Web安全史上的一個重要里程碑是大約1999年發現的SQL注入攻擊,之後的XSS,CSRF等攻擊手段愈發強大,Web攻擊的思路也從服務端轉向了客戶端,轉向了瀏覽器和

AOP實踐--ASP.NET MVC 5使用Filter過濾Action引數防止sql注入,讓你程式碼安全簡潔

在開發程式的過程中,稍微不注意就會隱含有sql注入的危險。今天我就來說下,ASP.NET mvc 5使用Filter過濾Action引數防止sql注入,讓你程式碼安全簡潔。不用每下地方對引數的值都進行檢查,看是使用者輸入的內容是否有危險的sql。如果沒個地方都要加有幾個缺

PHP PDO 防止SQL注入

使用PDO的好處: 1> 防止SQL注入 2> 提高執行效率 每條SQL執行前,MYSQL資料庫都需要先進行編譯(即便是一個空格也可能引起重新編譯)。在迴圈執行多條資料時,使用prepare方式傳入不同引數可以減少編譯時間 大部分常見資料庫都支援prepare語

JDBC使用PreparedStatement防止SQL注入

   1.關於SQL注入 什麼是SQL注入: 由於jdbc程式在執行的過程中sql語句在拼裝時使用了由頁面傳入引數,如果使用者惡意傳入一些sql中的特殊關鍵字,會導致sql語句意義發生變化,這種攻擊方式就叫做sql注入,參考使用者註冊登入案例。   首先看一下以下程式碼:

php學習筆記(二十)mysqli的stmt的預處理類的使用(防止sql注入問題)

<?php /** * 處理資料庫的擴充套件庫 * * mysqli的預處理語句 * mysqli_stmt預處理類(推薦使用的類) * 優點:(mysqli和mysqli_result類的相比

php防止SQL注入的最好方法是什麼?

如果使用者輸入的是直接插入到一個SQL語句中的查詢,應用程式會很容易受到SQL注入,例如下面的例子: $unsafe_variable = $_POST['user_input']; mysql_query("INSERT INTO table (column) VAL

PHP】使用引數繫結防止SQL注入

<html> <head> <title>Sql注入演示</title> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <

PHP防止SQL注入的方法

【一、在伺服器端配置】        安全,PHP程式碼編寫是一方面,PHP的配置更是非常關鍵。 我們php手手工安裝的,php的預設配置檔案在 /usr/local/apache2/conf/php.ini,我們最主要就是要配置php.ini中的內容,讓我們執行 php能夠更安全。整個P