帳號密碼驗證

在 Web 領域裡,要在公開服務上對一般的使用者做身分驗證,最常見的實作即帳號密碼驗證。包括 GoogleFacebookAppleID 等,都是使用帳號密碼驗證。

這裡的「一般的使用者」,指的是網頁服務的使用者,通常 HTTP 的任務會交由 User Agent 來代為發送 HTTP 請求與接受回應並處理。

Access Authentication Framework

此方法最一開始是 1997 年定義在 RFC 2069,後來 1999 年在 RFC 2617 重新定義,接著 2014 年 RFC 7235 再一次重新定義。

這裡有個有趣的地方在,先前在簡介 HTTP 協定時,曾提到 HTTP/1.1 在 RFC 上的定義是從 RFC 2068RFC 2616,最後才是 RFC 7230 ~ RFC 7235。而 Access Authentication Framework 的定義一直都是跟隨著在 HTTP 協定之後,這也可以看得出身分驗證在 HTTP 被設計的時候就已經有在考慮了。

它的流程如下:

@startuml
Alice -> Bob: Get / HTTP/1.1
Alice <- Bob: HTTP/1.1 401 Unauthorized
Alice -> Alice: Challenge
Alice -> Bob: Get / HTTP/1.1 with Authorization header
Alice <- Bob: HTTP/1.1 200 OK
@enduml

它的好處是,因為它跟隨著最開始的 HTTP 協定一起發布,因此理論上支援度是最高的。只是有許多未考慮的情境,如它是明文傳輸,因此需要 TLS 避免使用者憑證(credentials)外泄等;另外,驗證完成後,憑證一直會保存到瀏覽器關閉,換言之,登出的唯一手段就是關閉瀏覽器。這對想繼續維持登入狀態,或想登出但又不想關閉瀏覽器來說,都非常麻煩。

即便這個方法有些安全性問題,但支援度高的關係,一般內部信任網域的服務常會採用這個方法。

HTTP + HTML Form-based Authentication

基於 HTTP + HTML 表單驗證這個方法只有在維基百科裡提到,IETF 並沒有特別定義這個方法,但是它是目前最常用的方法,主因是因為 Access Authentication Framework 的規範只實現在瀏覽器的彈出視窗裡,並且只有使用者和密碼兩個欄位,客製化畫面呈現或流程是完全沒有方法的。只是在使用 HTTP + HTML 表單驗證時,必須要了解相關的安全注意事項。

HTTP + HTML 表單驗證的流程描述如下。

  1. 未驗證的使用者想使用服務,服務會回傳 HTML 網頁,裡面包含了帶有使用者憑證資訊(如帳號、密碼等)輸入與提交按鈕的表單
  2. 使用者填寫憑證資訊,並點擊提交按鈕;同時 User Agent 將表單資訊傳送給 Web 服務器
  3. Web 服務器回傳驗證結果

流程圖如下:

@startuml
Alice -> Bob: Get / HTTP/1.1 with Challenge Form
Alice <- Bob: HTTP/1.1 200 OK with login state Cookie
Alice -> Bob: Get / HTTP/1.1 with login state Cookie
@enduml

表單的內容範例如下:

<form method="POST" action="/login">
<input type="text" name="username" required>
<input type="password" name="password" required>
<button type="submit">Login</button>
</form>

安全注意事項

使用這個方法,首要的問題依然是:HTTP 是明文傳輸,需要 TLS 避免攻擊者竊取傳輸內容。

再來如一開始所說,雖然 HTML 或 HTTP 都有標準可以依循,但兩者結合一起做身分驗證這個方法並沒有標準化。因此正常來說,使用者或 User Agent 並不知道今天連線的 Web 服務器是如何做身分驗證的。

最後,這個技術非常容易實現網路釣魚,因為它建立在「使用者準確地訪問正確的網址」上,來避免使用者憑證外泄,但事實上使用者通常辦不到,這同時也是為何網路釣魚是一個很常見的安全漏洞。

HTTP 協定是無狀態的,因此如果沒有 Cookie 的協助,會變成每次都要重打帳號密碼。但使用 Cookie 的同時,記得詳閱 Cookie 的安全隱患,以確保系統沒有漏洞讓攻擊者可以趁虛而入。

參考資料