用 PHP 實現 HTTP 身份驗證
阿恆
HTTP 身份驗證 (HTTP authentication) 是一種十分常用而容易實作的驗證方法,它倚賴網頁伺服器的內置功能,大量縮短所需編寫的程式碼,對於用戶驗證的要求不高的系統,是一個很實用的驗證方法。Evert Pot 在他的[網誌][1]上討論了如何用 PHP 實作這種用戶驗證。
基本驗證 (Basic Auth)
HTTP 身份驗證有兩個主要的驗證方案:「基本驗證 (basic authentication)」和「摘要驗證 (digest authentication)」,其中基本驗證比較容易實作,所以也比較常見,以下是一個以 PHP 實作的基本驗證:
|
|
這不算很複雜,是嗎?請注意用戶名稱和密碼都是用 base64 編碼後傳送到伺服器,除非你的伺服器使用 SSL,否則這不算十分安全。
摘要驗證 (Digest Auth)
摘要驗證旨在使驗證的過程更安全,驗證的過程中密碼永遠不會以明碼方式傳送,它以一個散列的形式被送到伺服器,散列的好處是它不能被還原為明碼,我們只能以相同的散列函式來計算儲存在伺服器上的密碼,透過比較兩個散列值來進行驗證,若過兩者相同便表示密碼正確。我們首先看看摘要驗證如何運作:
客戶端請求的 URL:
|
|
伺服器要求身份驗證:
|
|
客戶端驗證:
|
|
來自伺服器的訊息:
來自客戶端的訊息:
我們如何檢查密碼是否正確呢?以下的算法可以用來進行驗證:
|
|
用 PHP 來寫便是這樣:
|
|
正如你看到,我們需要明碼版本的用戶密碼來計算散列值,但是從系統安全的角度,把用戶的密碼儲存在伺服器並非好主意,所以強烈推薦儲存 $A1 的值。
安全改進
- 每次客戶端送來請求的時候,最好順便檢查 opaque、nonce 和 realm 的值,若果伺服器儲存了這些資料,為甚麼不檢查?
- nc 的數值應該越來越大,建議在伺服器儲存這個數值,並確保它沒有任何突然大的跳躍,它未必會嚴格的順序遞增,由於網絡的性質,你收到的數值偶然會缺少一個,或者沒有按順序。
- qop 是一個質量參數,如果 qop 設定為 auth,只有請求的 uri 會被散列函式使用,如果 qop 是 auth-int,請求的內容亦會被散列函式使用。(A2 = md5(request-method:uri:md5(request-body))
註銷驗證
伺服器只要再次送出 HTTP 401,瀏覽器便會註銷先前的驗證資料,從新要求用戶驗證。