在 Web 領域裡,要在公開服務上對一般的使用者做身分驗證,最常見的實作即帳號密碼驗證。包括 Google、Facebook、AppleID 等,都是使用帳號密碼驗證。
這裡的「一般的使用者」,指的是網頁服務的使用者,通常 HTTP 的任務會交由 User Agent 來代為發送 HTTP 請求與接受回應並處理。
此方法最一開始是 1997 年定義在 RFC 2069,後來 1999 年在 RFC 2617 重新定義,接著 2014 年 RFC 7235 再一次重新定義。
這裡有個有趣的地方在,先前在簡介 HTTP 協定時,曾提到 HTTP/1.1 在 RFC 上的定義是從 RFC 2068 到 RFC 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 表單驗證這個方法只有在維基百科裡提到,IETF 並沒有特別定義這個方法,但是它是目前最常用的方法,主因是因為 Access Authentication Framework 的規範只實現在瀏覽器的彈出視窗裡,並且只有使用者和密碼兩個欄位,客製化畫面呈現或流程是完全沒有方法的。只是在使用 HTTP + HTML 表單驗證時,必須要了解相關的安全注意事項。
HTTP + HTML 表單驗證的流程描述如下。
流程圖如下:
@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 的安全隱患,以確保系統沒有漏洞讓攻擊者可以趁虛而入。