| 特性 | 表單驗證 | HTTP 認證 |
|---|---|---|
| 實現層級 | 應用層(PHP 代碼控制) | HTTP 協議層(瀏覽器原生對話框) |
| 用戶體驗 | 自定義登入頁、錯誤提示、記住我、驗證碼 | 瀏覽器彈窗,樣式不可控,無法登出(需關閉瀏覽器) |
| 安全性 | 需自行防 CSRF、XSS、暴力破解 | Basic 傳輸 Base64(明文等效),必須配合 HTTPS;Digest 較安全 |
| 適用場景 | 絕大多數 Web 應用 | 內部 API、管理介面、WebDAV、RPC 端點 |
| PHP 依賴 | 無特殊要求 | 僅 Apache 模組模式(mod_php)有效,CGI/FPM 不支援 PHP_AUTH_* 變數 |
<?php
// 受保護頁面
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
exit('取消登入');
}
// 驗證用戶名/密碼(實際查資料庫)
if ($_SERVER['PHP_AUTH_USER'] !== 'admin' || $_SERVER['PHP_AUTH_PW'] !== 'secret') {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
exit('帳號密碼錯誤');
}
echo "歡迎,{$_SERVER['PHP_AUTH_USER']}!";
Digest 以挑戰-回應機制避免明文傳輸密碼,流程:
401 + WWW-Authenticate: Digest realm="...", nonce="...", qop="auth", opaque="..."response = MD5(MD5(user:realm:pass):nonce:nc:cnonce:qop:MD5(method:uri))$_SERVER['PHP_AUTH_DIGEST'],同樣算法驗證 response。<?php
$realm = 'Restricted area';
$users = ['admin' => 'mypass', 'guest' => 'guest'];
if (!isset($_SERVER['PHP_AUTH_DIGEST'])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.'", qop="auth", nonce="'.uniqid().'", opaque="'.md5($realm).'"');
die('認證失敗');
}
// 解析 Digest 標頭
preg_match_all('@(\w+)=(?:(?:\"([^\"]+)\")|([^\s,]+))@', $_SERVER['PHP_AUTH_DIGEST'], $matches, PREG_SET_ORDER);
$digest = [];
foreach ($matches as $m) $digest[$m[1]] = $m[2] ?? $m[3];
if (!isset($users[$digest['username']])) die('用戶不存在');
// 計算合法 response
$A1 = md5("{$digest['username']}:$realm:{$users[$digest['username']]}");
$A2 = md5("{$_SERVER['REQUEST_METHOD']}:{$digest['uri']}");
$valid = md5("$A1:{$digest['nonce']}:{$digest['nc']}:{$digest['cnonce']}:{$digest['qop']}:$A2");
if ($digest['response'] !== $valid) die('憑證錯誤');
echo "登入成功:{$digest['username']}";
HTTP 認證無原生登出,常用手法:
realm 迫使瀏覽器重新彈窗。401 並提示用戶點擊「取消」後重新載入。fetch('/logout', {credentials: 'include'}) 但瀏覽器仍會快取憑證。<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="Test System"');
header('HTTP/1.0 401 Unauthorized');
exit('請重新登入');
}
if (!isset($_SERVER['PHP_AUTH_USER']) ||
(isset($_POST['SeenBefore']) && $_POST['OldAuth'] === $_SERVER['PHP_AUTH_USER'])) {
authenticate();
}
echo "歡迎,{$_SERVER['PHP_AUTH_USER']}";
echo "<form method='post'><input type='hidden' name='SeenBefore' value='1'>
<input type='hidden' name='OldAuth' value='{$_SERVER['PHP_AUTH_USER']}'>
<button type='submit'>重新認證</button></form>";
<input name="csrf_token" value="= $_SESSION['csrf'] ?>">,驗證時比對。password_hash($pwd, PASSWORD_DEFAULT) 存儲,password_verify($input, $hash) 驗證。$_SERVER['HTTPS'] !== 'on' 時導向 HTTPS。setcookie('remember', $token, time()+30*86400, '/', '', true, true),資料庫存 selector:hash(token)。$_SERVER['PHP_AUTH_USER'] 可用。auth_basic 或改用表單驗證。PHP_AUTH_* 不會被填充。PHP_AUTH_* 可能被阻擋,可用 $_SERVER['REMOTE_USER']。HTTP 認證適合簡單、內部、機器對機器場景;表單驗證是面向用戶 Web 應用的標準。現代專案強烈建議採用表單驗證 + HTTPS + 密碼雜湊 + CSRF 保護 + 限流,並在 API 端點使用 Bearer Token (JWT/OAuth2)。