401 Unauthorized,附帶 WWW-Authenticate: Digest realm="...", nonce="...", algorithm=MD5, qop="auth"。response = MD5(A1:nonce:nc:cnonce:qop:A2) 並送回 Authorization 標頭。response 比對,一致則驗證通過。A1 = MD5(username:realm:password)
A2 = MD5(method:uri)
response = MD5(A1:nonce:nc:cnonce:qop:A2)
<?php
$realm = 'MyRealm';
if (!isset($_SERVER['PHP_AUTH_DIGEST'])) {
header('WWW-Authenticate: Digest realm="'.$realm.'",nonce="'.uniqid().'",algorithm=MD5,qop="auth"');
header('HTTP/1.0 401 Unauthorized');
exit('認證失敗');
}
$data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST']);
if (!$data) {
header('HTTP/1.0 401 Unauthorized');
exit('解析失敗');
}
// 從資料庫查詢真實密碼,此處示範寫死
$A1 = md5('admin:'.$realm.':password');
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
if ($data['response'] === $valid) {
echo '驗證通過!';
} else {
header('HTTP/1.0 401 Unauthorized');
exit('帳號/密碼錯誤');
}
function http_digest_parse($txt) {
$need = ['nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1];
preg_match_all('@(\w+)=(["\']?)([^"\']+)\2@', $txt, $m, PREG_SET_ORDER);
$data = [];
foreach ($m as $v) {
$data[$v[1]] = $v[3];
unset($need[$v[1]]);
}
return $need ? false : $data;
}
?>
nc (nonce-count) 需檢查遞增,防重複使用。algorithm=SHA-256 或 SHA-512-256(RFC 7616),PHP 需自行實作對應雜湊。Digest 認證雖比 Basic 安全,但實作複雜且仍有已知弱點。現代 Web 應優先採用 OAuth 2.0 / JWT / Session-Cookie 等成熟方案,Digest 適用於無法部署 HTTPS 的舊式內網設備或 API 相容場景。