HTTP認證模式:Basic & Digest

天府雲創發表於2019-04-23

引言

經常在工作中使用到了各種認證方式,但從未考慮過這些認證方式所屬的知識範疇,同時也解釋不清楚它們。

曾用到的認證方式(看看是否您也用過,但很難解釋清楚他們):

  • Basic認證(訪問API時,瀏覽器會自動彈出一個對話方塊去輸入使用者名稱/密碼)
  • 使用者名稱密碼認證(進入站點主頁前,需要在登陸頁面輸入使用者名稱和密碼,這種更專業的叫法為表單認證)
  • openID Connect認證(用於第三方登陸認證,比如微信提供給簡書的登入認證)
  • Kerberos認證(一種用於Hadoop叢集的客戶端認證)

經過閱讀《圖解HTTP協議》這一書後,對HTTP認證方式有了進一步的瞭解。

1.  basic認證是把使用者和密碼通過base64加密後傳送給伺服器進行驗證

2.  digest認證則是把伺服器響應的401訊息裡面的特定的值和使用者名稱以及密碼結合起來進行不可逆的摘要演算法運算得到一個值,然後把使用者名稱和這個摘要值發給伺服器,服務通過使用者名稱去 在自己本地找到對應的密碼,然後進行同樣的摘要運算,再比較這個值是否和客戶端發過來的摘要值一樣。

TTP協議規範的另一種認證模式是Digest模式,在HTTP1.1時被提出來,它主要是為了解決Basic模式安全問題,用於替代原來的Basic認證模式,Digest認證也是採用challenge/response認證模式,基本的認證流程比較類似,整個過程如下:

①瀏覽器傳送http報文請求一個受保護的資源。

②服務端的web容器將http響應報文的響應碼設為401,響應頭部比Basic模式複雜,WWW-Authenticate: Digest realm=”myTomcat”,qop="auth",nonce="xxxxxxxxxxx",opaque="xxxxxxxx" 。其中qop的auth表示鑑別方式;nonce是隨機字串;opaque服務端指定的值,客戶端需要原值返回。

③瀏覽器彈出對話方塊讓使用者輸入使用者名稱和密碼,瀏覽器對使用者名稱、密碼、nonce值、HTTP請求方法、被請求資源URI等組合後進行MD5運算,把計算得到的摘要資訊傳送給服務端。請求頭部類似如下,Authorization: Digest username="xxxxx",realm="myTomcat",qop="auth",nonce="xxxxx",uri="xxxx",cnonce="xxxxxx",nc=00000001,response="xxxxxxxxx",opaque="xxxxxxxxx" 。其中username是使用者名稱;cnonce是客戶端生成的隨機字串;nc是執行認證的次數;response就是最終計算得到的摘要。

④服務端web容器獲取HTTP報文頭部相關認證資訊,從中獲取到username,根據username獲取對應的密碼,同樣對使用者名稱、密碼、nonce值、HTTP請求方法、被請求資源URI等組合進行MD5運算,計算結果和response進行比較,如果匹配則認證成功並返回相關資源,否則再執行②,重新進行認證。

⑤以後每次訪問都要帶上認證頭部。

其實通過雜湊演算法對通訊雙方身份的認證十分常見,它的好處就是不必把具備密碼的資訊對外傳輸,只需將這些密碼資訊加入一個對方給定的隨機值計算雜湊值,最後將雜湊值傳給對方,對方就可以認證你的身份。Digest思想同樣採如此,用了一種nonce隨機數字符串,雙方約好對哪些資訊進行雜湊運算即可完成雙方身份的驗證。Digest模式避免了密碼在網路上明文傳輸,提高了安全性,但它仍然存在缺點,例如認證報文被攻擊者攔截到攻擊者可以獲取到資源.

HTTP請求報頭: Authorization

HTTP響應報頭: WWW-Authenticate

 

HTTP認證 

基於

 質詢 /迴應( 

challenge/response)的認證模式。

 

◆ 基本認證 basic authentication   ← HTTP1.0提出的認證方法

    客戶端對於每一個realm,通過提供使用者名稱和密碼來進行認證的方式。

    ※ 包含密碼的明文傳遞

 

    基本認證步驟:

     1. 客戶端訪問一個受http基本認證保護的資源。

     2. 伺服器返回401狀態,要求客戶端提供使用者名稱和密碼進行認證。

           401 Unauthorized

           WWW-Authenticate: Basic realm="WallyWorld"

     3. 客戶端將輸入的使用者名稱密碼用Base64進行編碼後,採用非加密的明文方式傳送給伺服器。

           Authorization: Basic xxxxxxxxxx.

     4. 如果認證成功,則返回相應的資源。如果認證失敗,則仍返回401狀態,要求重新進行認證。

 

    特記事項

     1. Http是無狀態的,同一個客戶端對同一個realm內資源的每一個訪問會被要求進行認證。

     2. 客戶端通常會快取使用者名稱和密碼,並和authentication realm一起儲存,所以,一般不需要你重新輸入使用者名稱和密碼。

     3. 以非加密的明文方式傳輸,雖然轉換成了不易被人直接識別的字串,但是無法防止使用者名稱密碼被惡意盜用。

 

◆ 摘要認證 digest authentication   ← HTTP1.1提出的基本認證的替代方法

    伺服器端以nonce進行質詢,客戶端以使用者名稱,密碼,nonce,HTTP方法,請求的URI等資訊為基礎產生的response資訊進行認證的方式。

    ※ 不包含密碼的明文傳遞

    

    摘要認證步驟:

     1. 客戶端訪問一個受http摘要認證保護的資源。

     2. 伺服器返回401狀態以及nonce等資訊,要求客戶端進行認證。

HTTP/1.1 401 Unauthorized

WWW-Authenticate: Digest

realm="testrealm@host.com",

qop="auth,auth-int",

nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",

opaque="5ccc069c403ebaf9f0171e9517f40e41"

     3. 客戶端將以使用者名稱,密碼,nonce值,HTTP方法, 和被請求的URI為校驗值基礎而加密(預設為MD5演算法)的摘要資訊返回給伺服器。

           認證必須的五個情報:

     ・ realm : 響應中包含資訊

     ・ nonce : 響應中包含資訊

     ・ username : 使用者名稱

     ・ digest-uri : 請求的URI

     ・ response : 以上面四個資訊加上密碼資訊,使用MD5演算法得出的字串。

 

Authorization: Digest 

username="Mufasa",  ← 客戶端已知資訊

realm="testrealm@host.com",   ← 伺服器端質詢響應資訊

nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",  ← 伺服器端質詢響應資訊

uri="/dir/index.html", ← 客戶端已知資訊

qop=auth,   ← 伺服器端質詢響應資訊

nc=00000001, ← 客戶端計算出的資訊

cnonce="0a4f113b", ← 客戶端計算出的客戶端nonce

response="6629fae49393a05397450978507c4ef1", ← 最終的摘要資訊 ha3

opaque="5ccc069c403ebaf9f0171e9517f40e41"  ← 伺服器端質詢響應資訊

     4. 如果認證成功,則返回相應的資源。如果認證失敗,則仍返回401狀態,要求重新進行認證。

 

    特記事項:

     1. 避免將密碼作為明文在網路上傳遞,相對提高了HTTP認證的安全性。

     2. 當使用者為某個realm首次設定密碼時,伺服器儲存的是以使用者名稱,realm,密碼為基礎計算出的雜湊值(ha1),而非密碼本身。

     3. 如果qop=auth-int,在計算ha2時,除了包括HTTP方法,URI路徑外,還包括請求實體主體,從而防止PUT和POST請求表示被人篡改。

     4. 但是因為nonce本身可以被用來進行摘要認證,所以也無法確保認證後傳遞過來的資料的安全性。

 

   ※ nonce:隨機字串,每次返回401響應的時候都會返回一個不同的nonce。 

   ※ nounce:隨機字串,每個請求都得到一個不同的nounce。 

      ※ MD5(Message Digest algorithm 5,資訊摘要演算法)

         ① 使用者名稱:realm:密碼 ⇒ ha1

         ② HTTP方法:URI ⇒ ha2

         ③ ha1:nonce:nc:cnonce:qop:ha2 ⇒ ha3

 

◆ WSSE(WS-Security)認證  ← 擴充套件HTTP認證

   WSSE UsernameToken

    伺服器端以nonce進行質詢,客戶端以使用者名稱,密碼,nonce,HTTP方法,請求的URI等資訊為基礎產生的response資訊進行認證的方式。

    ※ 不包含密碼的明文傳遞

    

    WSSE認證步驟:

     1. 客戶端訪問一個受WSSE認證保護的資源。

     2. 伺服器返回401狀態,要求客戶端進行認證。

HTTP/1.1 401 Unauthorized

WWW-Authenticate: WSSE

realm="testrealm@host.com",

profile="UsernameToken" ← 伺服器期望你用UsernameToken規則生成迴應

※ UsernameToken規則:客戶端生成一個nonce,然後根據該nonce,密碼和當前日時來算出雜湊值。

     3. 客戶端將生成一個nonce值,並以該nonce值,密碼,當前日時為基礎,算出雜湊值返回給伺服器。

Authorization: WSSE profile="UsernameToken"

X-WSSE:UsernameToken

username="Mufasa",

PasswordDigest="Z2Y......",

Nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093",

Created="2010-01-01T09:00:00Z"

     4. 如果認證成功,則返回相應的資源。如果認證失敗,則仍返回401狀態,要求重新進行認證。

 

    特記事項:

     1. 避免將密碼作為明文在網路上傳遞。

     2. 不需要在伺服器端作設定。

     3. 伺服器端必須儲存密碼本身,否則無法進行身份驗證。

 

一. Basic 認證

  客戶端以“ : ”連線使用者名稱和密碼後,再經BASE64加密通過Authorization請求頭髮送該密文至服務端進行驗證,每次請求都需要重複傳送該密文。可見Basic認證過程簡單,安全性也低,存在洩露個人賬號資訊以及其他諸多安全問題。以下僅為原理演示,不代表真實情況:

  1. 客戶端向伺服器請求資料:

    GET / HTTP/1.1
    Host: www.myrealm.com

  2. 服務端向客戶端傳送驗證請求401:

    HTTP/1.1 401 Unauthorised
    Server: bfe/1.0.8.18
    WWW-Authenticate: Basic realm="myrealm.com"
    Content-Type: text/html; charset=utf-8

  3. 客戶端收到401返回值後,將自動彈出一個登入視窗,等待使用者輸入使用者名稱和密碼

  4. 將“使用者名稱:密碼”進行BASE64加密後傳送服務端進行驗證:

    GET / HTTP/1.1
    Host: www.myrealm.com
    Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxx

  5. 服務端取出Authorization請求頭資訊進行解密,並與使用者資料庫進行對比判斷是否合法,合法將返回200 OK。RFC 2617 規格中Basic認證不傳送Authentication-Info頭部,Authentication-Info頭部是Digest認證中新增的

 1 <?php 2   if (!isset($_SERVER[‘PHP_AUTH_USER‘])) { 3     header(‘WWW-Authenticate: Basic realm="My Realm"‘); 4     header(‘HTTP/1.0 401 Unauthorized‘); 5     echo ‘Text to send if user hits Cancel button‘; 6     exit; 7   } else { 8     echo "<p>Hello {$_SERVER[‘PHP_AUTH_USER‘]}.</p>"; 9     echo "<p>You entered {$_SERVER[‘PHP_AUTH_PW‘]} as your password.</p>";10   }

  

二. Digest 認證

  Digest認證試圖解決Basic認證的諸多缺陷而設計,使用者密碼在整個認證過程中是個關鍵性要素。

  下為服務端傳送的Digest認證響應頭部例項及各指令含義說明:PHP官方文件中傳送WWW-Authenticate頭部時各指令之間用了空格,在Chrome下是不會彈出認證對話方塊的,應該換成”, “或”,“

WWW-Authenticate: Digest realm="Restricted area", qop="auth,auth-int", nonce="58e8e52922398", opaque="cdce8a5c95a1427d74df7acbf41c9ce0", algorithm="MD5"
  • WWW-Authenticate:服務端傳送的認證質詢頭部

  • Authentication-Info:服務端傳送的認證響應頭部,包含nextnonce、rspauth響應摘要等

  • realm:授權域,至少應該包含主機名

  • domain:授權訪問URIs列表,項與項之間以空格符分隔

  • qop:質量保護,值為auth或auth-int或[token],auth-int包含對實體主體做完整性校驗

  • nonce:服務端產生的隨機數,用於增加摘要生成的複雜性,從而增加破解密碼的難度,防範“中間人”與“惡意伺服器”等攻擊型別,這是相對於不使用該指令而言的;另外,nonce本身可用於防止重放攻擊,用於實現服務端對客戶端的認證。RFC 2617 建議採用這個隨機數計算公式:nonce = BASE64(time-stamp MD5(time-stamp “:” ETag “:” private-key)),服務端可以決定這種nonce時間有效性,ETag(URL對應的資源Entity Tag,在CGI程式設計中通常需要自行生成ETag和鑑別,可用於鑑別URL對應的資源是否改變,區分不同語言、Session、Cookie等)可以防止對已更新資源版本(未更新無效,故需要設定nonce有效期)的重放請求,private-key為服務端私有key

  • opaque:這是一個不透明的資料字串,在盤問中傳送給客戶端,客戶端會將這個資料字串再傳送回服務端器。如果需要在服務端和客戶端之間維護一些狀態,用nonce來維護狀態資料是一種更容易也更安全的實現方式

  • stale:nonce過期標誌,值為true或false

  • algorithm:摘要演算法,值為MD5或MD5-sess或[token],預設為MD5

  下為客戶端傳送的Digest認證頭請求部例項及各指令含義說明:

Authorization: Digest username="somename", realm="Restricted area", nonce="58e8e52922398", uri="/t.php", response="9c839dde909d270bc5b901c7f80f77d5", opaque="cdce8a5c95a1427d74df7acbf41c9ce0", qop="auth", nc=00000001, cnonce="9c30405c3a67a259"
  • cnonce:客戶端產生的隨機數,用於客戶端對伺服器的認證。由於“中間人”與“惡意伺服器”等攻擊方式的存在,導致一個特意選擇而非隨機唯一的nonce值傳給客戶端用於摘要的計算成為可能,使得“選擇性明文攻擊”可能奏效,最後使用者密碼洩露。因此與nonce一樣,cnonce可用於增加摘要生成的複雜性,從而增加破解密碼的難度,也就保證了對服務端的認證

    The countermeasure against this attack(選擇明文攻擊) is for clients to be configured to require the use of the optional "cnonce" directive;this allows the client to vary the input to the hash in a way not chosen by the attacker.

     

  • nc:當服務端開啟qop時,客戶端才需要傳送nc(nonce-count)。服務端能夠通過維護nc來檢測用當前nonce標記的請求重放。如果相同的nc出現在用當前nonce標記的兩次請求中,那麼這兩次請求即為重複請求。所以對於防止重放攻擊而言,除了nonce之外,nc才是最後的保障。因此服務端除了維護使用者賬號資訊之外,還需要維護nonce和nc的關聯狀態資料

  下面將就摘要計算方法進行說明: 

  1. 演算法的一般性表示

    H(data) = MD5(data)
    KD(secret, data) = H(concat(secret, ":", data))
  2. 與安全資訊相關的資料用A1表示,則

    a) 採用MD5演算法:
        A1=(user):(realm):(password)
    b) 採用MD5-sess演算法:
        A1=H((user):(realm):(password)):nonce:cnonce
  3. 與安全資訊無關的資料用A2表示,則

    a) QoP為auth或未定義:
        A2=(request-method):(uri-directive-value)
    b) QoP為auth-int:
        A2=(request-method):(uri-directive-value):H((entity-body))
  4. 摘要值用response表示,則

     

    a) 若qop沒有定義:
        response
        = KD(H(A1),<nonce>:H(A2))
        = H(H(A1),<nonce>:H(A2))
    b) 若qop為auth或auth-int:
        response
        = KD(H(A1),<nonce>:<nc>:<cnonce>:<qop>:H(A2))
        = H(H(A1),<nonce>:<nc>:<cnonce>:<qop>:H(A2))
    

三、Form Based Authentication 表單認證 
表單提交認證:認證資訊作為請求引數,類似於Http基本認證

si. 安全風險

  • 線上字典攻擊(Online dictionary attacks):攻擊者可以嘗試用包含口令的字典進行模擬計算response,然後與竊聽到的任何nonce / response對進行對比,若結果一致則攻擊成功。為應對針對弱口令的字典攻擊,降低攻擊成功的可能性,可以禁止使用者使用弱口令

  • 中間人(Man in the Middle):在一次中間人攻擊中,一個弱認證方案被新增並提供給客戶端,因此你總是應該從多個備選認證方案中選擇使用最強的那一個;甚至中間人可能以Basic認證替換掉服務端提供的Digest認證,從而竊取到使用者的安全憑證,然後中間人可利用該憑證去響應服務端的Digest認證盤問;攻擊者還可能打著免費快取代理服務的幌子來招攬輕信者,通過實施中間人攻擊,盜取他們的安全憑證;中間代理也可能誘導客戶端來傳送一個請求給服務端。為此,客戶端可考慮給出安全等級風險警示,或在跟蹤服務端的認證配置時發現其認證強度降低就發出警告,或配置成只使用強認證,或從指定站點來完成認證

  • 預先計算字典攻擊(Precomputed dictionary attacks):攻擊者先構建(response, password) 對字典,然後用選擇性明文(nonce)攻擊的辦法來獲得相應盤問的response,檢索字典找到匹配的response則攻擊成功

  • 批量式暴力攻擊(Batch brute force attacks):中間人會對多個使用者執行選擇性明文攻擊來蒐集相應的responses,通過控制蒐集的nonce / response對的數量將會縮短找到第一個password的耗時,這種攻擊的應對之策就是要求客戶端使用cnonce指令

  • 假冒伺服器欺騙(Spoofing by Counterfeit Servers):對於Basic認證,這種攻擊方式更容易奏效,對於Digest認證則更難,但前提是客戶端必須知道將要使用的是Digest認證。使用者在所使用的認證機制中如何發現這一潛在攻擊樣式應該得到可見的幫助

【參考資料】

1、HTTP常用認證方式 - 簡書 https://www.jianshu.com/p/87a1322d325e

2、HTTP認證方式與https簡介 -部落格園 https://www.cnblogs.com/xzwblog/p/6834663.html

相關文章