PHP Conference Japan 2024

使用 PHP 進行 HTTP 驗證

可以使用 header() 函式向客戶端瀏覽器發送 "Authentication Required" 訊息,使其彈出使用者名稱/密碼輸入視窗。一旦使用者填寫了使用者名稱和密碼,包含 PHP 腳本的 URL 將再次被呼叫,並將 預定義變數 PHP_AUTH_USERPHP_AUTH_PWAUTH_TYPE 分別設定為使用者名稱、密碼和驗證類型。這些預定義變數可在 $_SERVER 陣列中找到。支援 "Basic" 驗證方法。有關詳細資訊,請參閱 header() 函式。

以下是一個腳本片段範例,它會在頁面上強制客戶端驗證

範例 #1 基本 HTTP 驗證範例

<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="我的領域"');
header('HTTP/1.0 401 Unauthorized');
echo
'如果使用者點擊「取消」按鈕時要發送的文字';
exit;
} else {
echo
"<p>哈囉 {$_SERVER['PHP_AUTH_USER']}。</p>";
echo
"<p>您輸入的密碼是 {$_SERVER['PHP_AUTH_PW']}。</p>";
}
?>

注意相容性注意事項

在編寫 HTTP 標頭行時請小心。為了保證與所有客戶端的最大相容性,關鍵字 "Basic" 應以大寫 "B" 書寫,領域字串必須以雙引號 (而非單引號) 括起來,且在 HTTP/1.0 401 標頭行中,401 代碼之前應恰好有一個空格。驗證參數必須以逗號分隔。

您可能想要檢查使用者名稱和密碼的有效性,而不是像上述範例那樣僅僅列印 PHP_AUTH_USERPHP_AUTH_PW。也許可以透過向資料庫發送查詢,或者在 dbm 檔案中查找使用者。

請注意那些有錯誤的 Internet Explorer 瀏覽器。它們似乎對標頭的順序非常挑剔。在 HTTP/1.0 401 標頭之前發送 WWW-Authenticate 標頭似乎目前可行。

注意組態注意事項

PHP 使用 AuthType 指令的存在來確定外部驗證是否有效。

但是請注意,以上方法並不能阻止控制未驗證 URL 的人從同一伺服器上的已驗證 URL 竊取密碼。

Netscape Navigator 和 Internet Explorer 在收到伺服器 401 回應時,都會清除領域的本機瀏覽器視窗驗證快取。這可以有效地「登出」使用者,迫使他們重新輸入使用者名稱和密碼。有些人會使用這種方式來「逾時」登入,或提供「登出」按鈕。

範例 #2 HTTP 驗證範例,強制使用新的使用者名稱/密碼

<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="測試驗證系統"');
header('HTTP/1.0 401 Unauthorized');
echo
"您必須輸入有效的登入 ID 和密碼才能存取此資源\n";
exit;
}

if (!isset(
$_SERVER['PHP_AUTH_USER']) ||
(
$_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
} else {
echo
"<p>歡迎: " . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "<br />";
echo
"舊的: " . htmlspecialchars($_REQUEST['OldAuth']);
echo
"<form action='' method='post'>\n";
echo
"<input type='hidden' name='SeenBefore' value='1' />\n";
echo
"<input type='hidden' name='OldAuth' value=\"" . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "\" />\n";
echo
"<input type='submit' value='重新驗證' />\n";
echo
"</form></p>\n";
}
?>

此行為並非 HTTP Basic 驗證標準所要求的,因此您不應過於依賴此行為。使用 Lynx 進行測試顯示,Lynx 不會清除伺服器 401 回應的驗證憑證,因此只要憑證要求沒有變更,按下「上一頁」然後再次按下「下一頁」,即可開啟資源。但是,使用者可以按下 '_' 鍵來清除其驗證資訊。

為了使 HTTP 驗證在使用 IIS 伺服器和 CGI 版本的 PHP 時正常運作,您必須編輯您的 IIS 組態「目錄安全性」。按一下「編輯」,並且僅勾選「匿名存取」,所有其他欄位應保持未勾選。

注意IIS 注意事項:
為了使 HTTP 驗證在 IIS 上正常運作,PHP 指令 cgi.rfc2616_headers 必須設定為 0 (預設值)。

新增註解

使用者貢獻的註解 46 則註解

74
derkontrollfreak+9hy5l at gmail dot com
10 年前
在 CGI/FastCGI Apache 下缺少 Authorization 標頭的解決方案

SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0

現在,如果客戶端傳送 Authorization 標頭,PHP 應自動宣告 $_SERVER[PHP_AUTH_*] 變數。
57
webmaster at kratia dot com
17 年前
這是我找到使用重試執行基本授權的最簡單形式。

<?php

$valid_passwords
= array ("mario" => "carbonell");
$valid_users = array_keys($valid_passwords);

$user = $_SERVER['PHP_AUTH_USER'];
$pass = $_SERVER['PHP_AUTH_PW'];

$validated = (in_array($user, $valid_users)) && ($pass == $valid_passwords[$user]);

if (!
$validated) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
die (
"Not authorized");
}

// If arrives here, is a valid user.
echo "<p>Welcome $user.</p>";
echo
"<p>Congratulation, you are into the system.</p>";

?>
25
roychri at php dot net
18 年前
對於使用 CGI 的 PHP,請確保將重寫規則放在您可能擁有的任何其他重寫規則之上。

在我的情況下,我將此放在 .htaccess 的頂部(在 RewriteEngine On 之下)
RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]

我的症狀是根本沒有設定 REMOTE_USER (或在我的情況下是 REDIRECT_REMOTE_USER)。
原因:我有一些其他的 RewriteRule 正在啟動,並且設定為 LAST 規則。
我希望這有幫助。
32
kazakevichilya at gmail dot com
12 年前
如果是 CGI/FastCGI,您將無法存取 PHP_AUTH* 資訊,因為 CGI 協議沒有宣告這些變數(這就是它們的名稱以 PHP 開頭的原因),而且伺服器不會將它們傳遞給直譯器。在 CGI 中,伺服器應該自己驗證使用者身分,並在其驗證後將 REMOTE_USER 傳遞給 CGI 腳本。

因此,您需要「取得」請求標頭,並以某種方式將它們傳遞給您的腳本。

在 apache 中,如果安裝了 mod_env,您可以透過環境變數來執行此操作。

以下 .htaccess 中的建構會將請求標頭 "Authorization" 複製到 env 變數 PHP_AUTH_DIGEST_RAW

SetEnvIfNoCase ^Authorization$ "(.+)" PHP_AUTH_DIGEST_RAW=$1

您現在可以透過 $_ENV 來存取它。

請不要忘記從您的 env 變數中刪除驗證類型(在我的情況下為 "Digest"),因為 PHP_AUTH_DIGEST 沒有它。

如果沒有安裝 mod_env,您可能會有 mod_rewrite(因為「人類可讀的 URL」,每個人都有)。

您可以使用重寫規則來取得標頭並將其作為 GET 參數傳遞

RewriteRule ^.*$ site.php?PHP_AUTH_DIGEST_RAW=%{HTTP:Authorization} [NC,L]

在這裡,HTTP 請求標頭 Authorization 將透過 $_GET 作為 PHP_AUTH_DIGEST_RAW 來存取。

---
如果您使用 ZF,您可能會使用 Zend_Auth_Adapter_Http 來驗證使用者。

它使用 "Zend_Controller_Request::getHeader" 來取得 Authorization 資訊
此方法使用 apache_request_header,在舊的 CGI/FastCGI 安裝中或 _$_SERVER['HTTP_<HeaderName>] 可能無法存取,因此您需要將透過 _GET 或 ENV 取得的驗證資料放入
_$_SERVER['HTTP_AUTHORIZATION']。
這將使 ZF 透明地使用您的解決方案,而且我相信任何其他架構也應該可以使用
23
gbelyh at gmail dot com
17 年前
回到 CGI 模式中的授權。這是一個完整可用的範例

# 建立具有以下內容的 .htaccess 檔案
# 您也可以使用條件 (在此頁面中搜尋)
RewriteEngine on
RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]

# 在腳本開頭檢查授權的地方放置程式碼

$userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"],6)) ;

$userpass = explode(":", $userpass);

if ( count($userpass) == 2 ){
#這個部分並非適用於所有情況。
#print_r($userpass);die; #<- 這有助於找出正確的使用者名稱和密碼
list($name, $password) = explode(':', $userpass);
$_SERVER['PHP_AUTH_USER'] = $name;
$_SERVER['PHP_AUTH_PW'] = $password;

}
21
Anonymous
15 年前
Example #2 中的 http_digest_parse 中的 regex 對我不起作用 (PHP 5.2.6),因為在字元類別中不允許回溯參照。這個對我有效

<?php

// function to parse the http auth header
function http_digest_parse($txt)
{
// protect against missing data
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();

preg_match_all('@(\w+)=(?:(?:\'([^\']+)\'|"([^"]+)")|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);

foreach (
$matches as $m) {
$data[$m[1]] = $m[2] ? $m[2] : ($m[3] ? $m[3] : $m[4]);
unset(
$needed_parts[$m[1]]);
}

return
$needed_parts ? false : $data;
}

?>
20
vog at notjusthosting dot com
12 年前
您不應該在 RewriteRule 中使用「最後一個」(“L”) 指令!這會在每次提供基本或摘要驗證時防止跳過所有進一步的重寫規則,這幾乎肯定不是您想要的。

因此,以下幾行對於 .htaccess (或 httpd.conf) 檔案已足夠

RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
21
john_2232 at gmail dot com
9 年前
這是我嘗試建立一個摘要驗證類別,該類別將在不使用 cookie、session、db 或檔案的情況下登入和登出使用者。核心是這個簡單的程式碼,可將摘要字串剖析為適用於多個瀏覽器的變數。
<?php
// Tony Wyatt 於 2007 年 6 月 21 日撰寫,用於支援多瀏覽器解析摘要
public function explodethedigest($instring) {
$quote = '"';
$equal = '=';
$comma = ',';
$space = ' ';
$a = explode( $comma, $instring);
$ax = explode($space, $a[0]);
$b = explode( $equal, $ax[1], 2);
$c = explode( $equal, $a[1], 2);
$d = explode( $equal, $a[2], 2);
$e = explode( $equal, $a[3], 2);
$f = explode( $equal, $a[4], 2);
$g = explode( $equal, $a[5], 2);
$h = explode( $equal, $a[6], 2);
$i = explode( $equal, $a[7], 2);
$j = explode( $equal, $a[8], 2);
$k = explode( $equal, $a[9], 2);
$l = explode( $equal, $a[10], 2);
$parts = array(trim($b[0])=>trim($b[1], '"'), trim($c[0])=>trim($c[1], '"'), trim($d[0])=>trim($d[1], '"'), trim($e[0])=>trim($e[1], '"'), trim($f[0])=>trim($f[1], '"'), trim($g[0])=>trim($g[1], '"'), trim($h[0])=>trim($h[1], '"'), trim($i[0])=>trim($i[1], '"'), trim($j[0])=>trim($j[1], '"'), trim($k[0])=>trim($k[1], '"'), trim($l[0])=>trim($l[1], '"'));

return
$parts;
}
?>
請試用 http://www.creativetheory.ca/ /tests/ta1.php。 使用者名稱為 test,密碼為 pass,或使用者名稱為 guest,密碼為 guest 登入。前往第二頁查看程式碼連結。歡迎提供意見、想法、建議或批評。
22
jake22 at gmail dot com
9 年前
我提出了另一種方法來解決瀏覽器快取 WWW 驗證憑證並產生登出問題的問題。雖然大多數瀏覽器都有某種清除此資訊的方法,但我更希望我的網站來處理這項任務,而不是依賴使用者的判斷。

即使使用 Lalit 建立隨機領域名稱的方法,仍然可以使用 Firefox 中的「上一頁」按鈕返回受保護的區域,因此該方法無效。這是我的解決方案

由於瀏覽器將憑證附加到特定的 URL,因此請使用虛擬路徑,其中路徑的某個元件實際上是 PHP 腳本,而其後的所有內容都是 URI 的一部分,例如

http://velocitypress.ca/some_dir/login.php/auth/8f631b92/

透過為 URL 的最後一個元件選擇不同的數字,可以欺騙瀏覽器,使其認為它們正在處理完全不同的網站,從而再次提示使用者輸入憑證。

請注意,使用隨機、不受限制的數字仍然允許使用者按下「上一頁」按鈕返回頁面。您應該在伺服器端檔案或資料庫中追蹤此數字,並在每次成功登入時重新產生它,以便最後一個數字失效。使用無效的數字可能會導致 403 回應,或者,根據您當天的心情,可能會導致 302 重導向到一個令人討厭的網站。

在這種情況下從產生的頁面連結時應謹慎,因為相對連結將相對於虛擬且不存在的目錄,而不是真正的腳本目錄。
17
bitman at bitworks dot de
3 年前
替代文字應包含(小)有效 HTML 資源的完整文字。它還可以包含到 CSS 的連結關係。
21
charly at towebs dot com
19 年前
關於以下貼文的更簡單方法
bernard dot paques at bigfoot dot com
2004 年 9 月 24 日 01:42

這是另一個解決 PHP 作為 CGI 執行時 PHP_AUTH_USER 和 PHP_AUTH_PW 伺服器變數問題的「修補程式」。

首先,請不要忘記在您的 .htaccess 中使用這段程式碼 (這是您使用 mod_rewrite 使其運作的唯一方法)

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]
</IfModule>

然後是 login.php

<?php
$a
= base64_decode( substr($_SERVER["REMOTE_USER"],6)) ;
if ( (
strlen($a) == 0) || ( strcasecmp($a, ":" ) == 0 ))
{
header( 'WWW-Authenticate: Basic realm="Private"' );
header( 'HTTP/1.0 401 Unauthorized' );
}
else
{
list(
$name, $password) = explode(':', $a);
$_SERVER['PHP_AUTH_USER'] = $name;
$_SERVER['PHP_AUTH_PW'] = $password;

}

echo
'PHP_AUTH_USER =' . $_SERVER['PHP_AUTH_USER'] . '<br>';
echo
'PHP_AUTH_PW =' . $_SERVER['PHP_AUTH_PW'] . '<br>';
echo
'REMOTE_USER =' . $_SERVER['REMOTE_USER'] . '<br>';
?>

首先,我們解碼 base64 編碼的字串,並捨棄 "Basic " 的前 6 個字元,然後進行常規驗證。
在腳本的末尾,我們印出變數以驗證它是否正常運作。這在產品版本中應該省略。

這是 Bernard Paques 腳本的變體。
感謝他提供這段程式碼。
22
Louis
18 年前
我無法讓任何範例的身份驗證正常運作。最後,我從 ZEND 的教學範例開始,網址在
http://www.zend.com/zend/tut/authentication.php?article=authentication (使用 .htpasswd 驗證),並嘗試處理其他情況。我總結的結論是,更改 realm 是唯一能讓瀏覽器再次詢問的可靠方法,我感謝在手冊中加入該範例的人,因為它讓我走上了正確的道路。無論如何,瀏覽器會拒絕捨棄它心中已有的值。當然,更改 realm 的問題是,您不希望在給定的會話中這樣做,否則會導致新的密碼請求。所以,這裡開始,希望間距不會因為複製貼上而太過混亂。

我花了一天的大部分時間來讓這個正常運作。我發現很難理解當瀏覽器遇到身份驗證請求時會做什麼:在我看來,它會嘗試獲取密碼,然後重新載入頁面...所以 HTML 不會被執行。至少,這是 IE 的情況,我還沒有用其他任何東西測試過。

<?php
session_start
() ;
if (!isset(
$_SESSION['realm'])) {
$_SESSION['realm'] = mt_rand( 1, 1000000000 ).
" SECOND level: Enter your !!!COMPANY!!! password.";

header( "WWW-Authenticate: Basic realm=".$_SESSION['realm'] );

// 下面的程式碼只有在沒有 $_SESSION 的情況下才會執行 HTML 部分,
// 而且瀏覽器通常 *無法* 設定 $PHP_AUTH_USER...
// 通常瀏覽器在取得授權資訊後,會再次執行頁面,而不會執行到這裡。
// 我基本上要說的是,來到這裡的方法是逃過登入畫面。我最初嘗試在此處放置 session_destroy(),但
// 問題是 PHP 無論如何都會執行,因此 REFRESH 似乎是處理它的最佳方法。
echo "<meta http-equiv=\"REFRESH\"
content=\"0;url=index.php\">"
;
exit;
}

if (
$_POST['logout'] == "logout") {
session_destroy() ;
header('Location: comeagain.php');
exit ;
}

// 這裡的 "標準" 驗證碼來自上面的 ZEND 教學。

comeagain.php 的內容如下:

<?
session_start();
unset(
$_SESSION['realm']);
session_destroy();
echo
"<html><head><title>Logged Out</title><h1>登出頁面</h1><body>" ;
echo
"您已成功登出 TOGEN";
echo
"於 ".date("h:m:s")." 在 ".date("d F Y") ;
echo
"<p><a href=\"index.php\">再次登入</a>" ;
echo
"</body></html>" ;
?>

這個想法是能夠刪除會話 (並因此重設 realm),而不會提示瀏覽器再次詢問...因為它已被重新導向至 logout.php。

透過這個組合,我讓事情運作了。只要確保不要同時讓 apache 執行 htpasswd 身份驗證,否則事情會變得非常奇怪 :-)。
22
php at cscott dot net
20 年前
請注意,微軟已發布「安全性更新」,停用在 http URL 中使用 username:password@host。

http://support.microsoft.com/default.aspx?scid=kb;en-us;834489

令人遺憾的是,上述依賴此方法的解決方案將無法在微軟瀏覽器中運作。

您可以依照以下說明重新啟用此功能:

http://weblogs.asp.net/cumpsd/archive/2004/02/07/69366.aspx

但您的使用者可能不願意這樣做。
18
sjeffrey at inquesis dot com
22 年前
若要使其在 IIS 中運作,請在設定您的 "$auth = 0" 和 "if (isset($PHP_AUTH_USER) && isset($PHP_AUTH_PW))" 之前嘗試使用此程式碼

<?php
//////////////////////////////////////////

if ($PHP_AUTH_USER == "" && $PHP_AUTH_PW == "" && ereg("^Basic ", $HTTP_AUTHORIZATION))
{
list(
$PHP_AUTH_USER, $PHP_AUTH_PW) =
explode(":", base64_decode(substr($HTTP_AUTHORIZATION, 6)));
}

//////////////////////////////////////////
?>

它在 ISAPI 中的 IIS 5 和 PHP 4 上對我來說有效
11
nuno at mail dot ideianet dot pt
20 年前
在 Windows 2003 Server/IIS6 上使用 php4+ cgi 時,我只能透過以下方式讓 HTTP 身份驗證正常運作:
<?php header("Status: 401 Access Denied"); ?>
使用
<?php header('HTTP/1.0 401 Unauthorized'); ?>
無效!
我還需要在「自訂錯誤」中選擇「401;1」到「401;5」的範圍,然後按一下「設定為預設」按鈕。
感謝 rob at theblip dot com
22
Nicolas Merlet - admin(at)merletn.org
17 年前
如果您必須在用 'http_digest_parse' 函數驗證回應 *之前* 使用 'setlocale' 函數,請小心使用 http digest 身份驗證 (請參閱上文,範例 34.2),因為在 'preg_match_all' 函數的模式中與 \w 發生衝突。

事實上,由於 \w 應該是任何字母或數字或底線字元,您必須記得這可能會因您的地區設定而異 (例如,它在法文中接受帶重音的字母)...

由於 'preg_match_all' 函數對模式的解讀不同,如果您已修改您的地區設定 (我的意思是,如果您的地區設定接受某些擴充字元,請參閱 http://fr.php.net/manual/en/reference.pcre.pattern.syntax.php 以取得更多資訊),則 'http_digest_parse' 函數將永遠會回傳錯誤結果。

恕我直言,我建議您不要在完成身份驗證之前使用 setlocale...

PS:這是一個不相容的 setlocale 宣告...
setlocale ( LC_ALL, 'fr_FR', 'fr', 'FR', 'french', 'fra', 'france', 'French', 'fr_FR.ISO8859-1' ) ;
25
Yuriy
15 年前
您好。
很抱歉我的英文不好。
這個範例顯示了如何編寫「登入」、「登出」和「重新登入」。
這個腳本必須在受保護的頁面中使用。
若要讓此腳本運作,瀏覽器網址字串必須如下所示:
"https://127.0.0.1/admin/?login" - 用於登入,
"https://127.0.0.1/admin/?logout" - 用於登出,
"https://127.0.0.1/admin/?logout&login" - 用於重新登入。
<?php
session_start
();

$authorized = false;

# 登出
if (isset($_GET['logout']) && !isset($_GET["login"]) && isset($_SESSION['auth']))
{
$_SESSION = array();
unset(
$_COOKIE[session_name()]);
session_destroy();
echo
"正在登出...";
}

# 檢查登入使用者名稱與密碼
if (isset($_SERVER['PHP_AUTH_USER']) && isset($_SERVER['PHP_AUTH_PW']))
{
$user = 'test';
$pass = 'test';
if ((
$user == $_SERVER['PHP_AUTH_USER']) && ($pass == ($_SERVER['PHP_AUTH_PW'])) && isset($_SESSION['auth']))
{
$authorized = true;
}
}

# 登入
if (isset($_GET["login"]) && !$authorized ||
# 重新登入
isset($_GET["login"]) && isset($_GET["logout"]) && !isset($_SESSION['reauth']))
{
header('WWW-Authenticate: Basic Realm="請登入"');
header('HTTP/1.0 401 Unauthorized');
$_SESSION['auth'] = true;
$_SESSION['reauth'] = true;
echo
"現在登入,不然就永遠別想點擊...";
exit;
}
$_SESSION['reauth'] = null;
?>
<h1>你已<? echo ($authorized) ? (isset($_GET["login"]) && isset($_GET["logout"]) ? '重新' : '') : '未'; ?>登入!</h1>
23
xsanychx at mail dot ru
12 年前
新的驗證機制

<?php
$login
= 'test_login';
$pass = 'test_pass';

if((
$_SERVER['PHP_AUTH_PW']!= $pass || $_SERVER['PHP_AUTH_USER'] != $login)|| !$_SERVER['PHP_AUTH_USER'])
{
header('WWW-Authenticate: Basic realm="測試驗證"');
header('HTTP/1.0 401 Unauthorized');
echo
'驗證失敗';
exit;
}
?>
17
Carlos
7 年前
針對 Apache HTTP Server 2.4.13 及更新版本中,CGI/FastCGI 下遺失授權標頭的較簡單解決方案

CGIPassAuth On

請勿啟用包含基本驗證的授權標頭,這非常不安全。
17
emmanuel dot keller at net2000 dot ch
21 年前
某些伺服器不支援 HTTP1.0 規範,並會產生錯誤 500(例如)。這發生在我上傳驗證腳本的伺服器上。

如果發生這種情況,您可以嘗試 HTTP1.1 標頭語法

<?php
header
("WWW-Authenticate: Basic realm=\"我的領域\"");
header('status: 401 Unauthorized');
?>
19
Robb_Bean at gmx dot net
10 年前
在德文範例 #2 (digest) 中,<?php $realm = "Geschützter Bereich"; ?>。就我測試所知,母音變音 ü 是有問題的,會導致密碼輸入無限迴圈。在我的案例中,它是以 UTF-8 編寫的。因此,我建議領域僅使用純 ASCII 字元。
19
SlamJam
18 年前
我使用了 Louis 的範例 (2006-06-03),它對我來說運作良好 (謝謝)。

但是,我新增了一些程式碼行,以確保使用者只會看到驗證視窗幾次

<?php
$realm
= mt_rand( 1, 1000000000)."@YourCompany";
$_SESSION['realm'] = $realm;

// 在開始時,當領域被定義時:
$_SESSION['CountTrials'] = 1;
?>

然後當需要檢查驗證時 (ZEND 教學課程)

<?php

// 不超過 3 次嘗試
if (!$auth) {
$_SESSION['CountTrials']++;
if (
$_SESSION['CountTrials'] == 4) {
session_destroy() ;
header('Location: noentry.php');
exit ;
} else {
header("WWW-Authenticate: Basic realm=".$_SESSION['realm']);
header("HTTP/1.0 401 Unauthorized");
echo
'需要授權。';
exit;
}
} else {
echo
'<P>您已授權!</P>';
}
?>

noentry.php 與 comeagain.php 略有不同。
20
Ome Ko
14 年前
如果沒有使用者以密碼登出,連線到http://logout:logout@<?=$_SERVER['HTTP_HOST'];?>/SECRET/ 會強制 /SECRET 目錄進行全新的登入。


[danbrown AT php DOT net 的附註:以下附註是由「匿名」在 2010 年 4 月 1 日新增的(雖然我們認為這不是愚人節的玩笑)。]

由於 M$ 的另一個廢話,此登出方法不再 100% 有效
http://support.microsoft.com/kb/834489
15
dan223 at gmail dot com
9 年前
一個用於 SSL 用戶端憑證驗證的簡單腳本,並具有基本驗證的後備機制。我在我的網站上使用 LDAP 伺服器來檢查使用者名稱/密碼和用戶端憑證到使用者的映射。

<?
// 檢查我們是否以及如何被驗證
if ($_SERVER['SSL_CLIENT_VERIFY'] != "SUCCESS") { // 未使用用戶端憑證
if ((!$_SERVER['PHP_AUTH_USER']) && (!$_SERVER['PHP_AUTH_PW'])) { // 未使用基本驗證登入
authenticate(); // 發送基本驗證標頭
}
}

if ($_SERVER['SSL_CLIENT_S_DN_CN'] != "chris") { // 檢查憑證的 CN 名稱

if (!(($_SERVER['PHP_AUTH_USER'] == "test") && ($_SERVER['PHP_AUTH_PW'] == "123"))) { // 檢查使用者名稱和密碼
authenticate(); // 因為使用者名稱和/或密碼不符,發送基本驗證標頭
}
}

phpinfo();

// 呼叫驗證顯示
function authenticate() {
Header("WWW-Authenticate: Basic realm=網站");
Header("HTTP/1.0 401 Unauthorized");
error401();
exit;
}
?>

請參閱我的網站 (http://velocitypress.ca/index.php?page=/manuals/),以取得有關 Apache 和 PHP 的用戶端憑證的更多詳細資訊。
16
h3ndrik
13 年前
在我的 php-cgi 配置中,在設定 RewriteRule 後,正確的變數將會是:$_SERVER['REDIRECT_HTTP_AUTHORIZATION']

所以 PhpCGI 的解決方法是
在您的 .htaccess 中設定

RewriteEngine on
RewriteRule .* - [env=HTTP_AUTHORIZATION:%{HTTP:Authorization},last]

Php 解決方法
<?php
// 為了解決 apache+php-cgi 的問題,設定 http 驗證標頭
if (isset($_SERVER['HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['HTTP_AUTHORIZATION'], $matches)) {
list(
$name, $password) = explode(':', base64_decode($matches[1]));
$_SERVER['PHP_AUTH_USER'] = strip_tags($name);
$_SERVER['PHP_AUTH_PW'] = strip_tags($password);
}

// 為了解決 apache+php-cgi 的問題,如果變數被 apache 重新命名,也設定 http 驗證標頭
if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && preg_match('/Basic\s+(.*)$/i', $_SERVER['REDIRECT_HTTP_AUTHORIZATION'], $matches)) {
list(
$name, $password) = explode(':', base64_decode($matches[1]));
$_SERVER['PHP_AUTH_USER'] = strip_tags($name);
$_SERVER['PHP_AUTH_PW'] = strip_tags($password);
}
?>
20
admin at isprohosting dot com
18 年前
這裡有一些 .htaccess 設定對我們來說是有效的 (cPanel + phpsuexec),除非其他方法都失敗了。或許這可以幫助其他人。

# 使用 ModRewrite 的 PHP (CGI 模式) HTTP 驗證
RewriteEngine on
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]

然後你需要一小段 PHP 程式碼來解析這一行,之後所有事情都會像使用 mod_php 一樣運作。

if (isset($_SERVER['HTTP_AUTHORIZATION']))
{
$ha = base64_decode( substr($_SERVER['HTTP_AUTHORIZATION'],6) );
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', $ha);
unset $ha;
}

請享用!
18
sergio dot carvalho at gmail dot com
9 年前
我發現清除 PHP_AUTH_DIGEST 或 PHP_AUTH_USER 和 PHP_AUTH_PW 憑證唯一有效的方法是呼叫 HTTP/1.1 401 Unauthorized 標頭。

function clear_admin_access(){
header('HTTP/1.1 401 Unauthorized');
die('管理員存取已關閉');
}
13
kembl at example dot com
18 年前
# 使用 ModRewrite 的 PHP (CGI 模式) HTTP 驗證
# 最正確的範例,使用標頭檢查是否為非空值
RewriteEngine on
RewriteCond %{HTTP:Authorization} !^$
RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}, \
E=PHP_AUTH_USER:%{HTTP:Authorization},L]
13
jason
20 年前
關於 tigran at freenet dot am 提供的 php+mysql 驗證程式碼

有一些安全上的弱點。

首先
$user

$pass

都是不安全的,它們可能會使此程式碼容易受到 SQL 注入攻擊,你應該始終移除兩者中的無效字元,或至少將它們編碼。

實際上,將密碼儲存為 MD5 雜湊值可以減少你保護它們的工作量。

第二個安全風險
同一個 mysql 使用者同時擁有更新和選取權限,甚至可能還有在你的驗證資料庫中插入資料的權限。
再次強調,SQL 注入攻擊可能會發生,而且最終使用者可能會更改使用者名稱、密碼或與此相關的任何其他內容。

第三個問題比較偏向效能方面,

你真的需要更新資料庫嗎?因為更新比選取慢,如果你每次存取頁面時都進行更新,你會付出一些速度上的代價。

一個選擇是,如果你想使用 sql (我認為 mysql 有這個功能),可以使用僅限記憶體的資料庫,並在記憶體中建立一個表格,為每個登入的使用者儲存一個唯一的 session 識別碼。或者,如果是一個單一的前端系統,你可以使用 db 檔案。
11
spam at angstzustaen dot de
3 年前
public function loginUser(){
$username = filter_var($_GET['username'],FILTER_SANITIZE_STRING);
$pw = filter_var($_GET['pw'],FILTER_SANITIZE_STRING);
$row = $this->userModel->selectUser($username);

if (password_verify($pw,$row['pw'])){
$_SESSION["userId"] = $row['id'];

$this->isLogin();
} else{
new Msg(true,"Benutzername und Passwort stimmen nicht überein!");
}

}

一個簡單的使用者登入範例
21
ceo at l-i-e dot com
14 年前
要使用 Basic Auth 強制登出,你可以將 Realm 變更為不同的 Realm。

這會在你伺服器上為新的 "Realm" 強制使用一組新的憑證。

你只需要追蹤 Realm 名稱以及使用者/密碼,並在他們登入和登出時將其更改為新的/隨機的名稱。

我相信這是 HTTP Basic Auth 中唯一 100% 保證登出的方法,如果這部分寫在文件中,這裡許多使用者貢獻的「錯誤」評論都可以刪除了。
12
snagnever at gmail dot com
19 年前
它會在每次存取頁面時強制進行驗證
(或許可以幫助某人)

<?
header("Expires: Sat, 01 Jan 2000 00:00:00 GMT");
header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT");
header("Cache-Control: post-check=0, pre-check=0",false);
header("Pragma: no-cache");
session_cache_limiter("public, no-store");
session_start();

function http_auth()
{
$_SESSION['AUTH'] = 1;
header('HTTP/1.0 401 Unauthorized');
header('WWW-Authenticate: Basic realm="sn4g auth system"');
// 當使用者點擊「取消」時要執行的動作
exit();
}

if( !isset($_SERVER['PHP_AUTH_USER']) or @$_SESSION['AUTH'] != 1 )
{
http_auth();
exit();
}

// 使用者登入後要執行的動作

// 其餘動作,必須清除 session 陣列
$_SESSION = array();
session_destroy();
?>
13
Lars Stecken
16 年前
對於任何嘗試上述摘要範例但無法使其運作的人。

對我來說,問題似乎在於 regex 中使用 '\' (反斜線) 的方法已過時,應該使用 '$' (美元符號) 來表示反向參考。此外,結果必須修剪掉剩餘的雙引號和單引號。

這是有效的範例

// 用於解析 http 驗證標頭的函式
function http_digest_parse($txt)
{

// 防止遺失資料
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();

preg_match_all('@(\w+)=(?:([\'"])([^$2]+)$2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);

foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? trim($m[3],"\",'") : trim($m[4],"\",'");
unset($needed_parts[$m[1]]);
}

return $needed_parts ? false : $data;
}

或許有更複雜的方法可以在 regex 中修剪引號,但我懶得去處理了 :-)

問候,Lars
12
djreficul at yahoo dot com
18 年前
嗯,我認為要使驗證正確運作很容易。我使用 session 變數來強制使用者每次造訪記錄區域時都進行驗證。

<?php
if (!isset ($_SESSION['firstauthenticate'])) {
session_start();
}
function
authenticate() {
header('WWW-Authenticate: Basic realm="Sistema autentificaci?n UnoAutoSur"');
header('HTTP/1_0 401 Unauthorized');
// header("Status: 401 Access Denied");
echo "Unauthorized\n";
exit;
}
if (!isset(
$_SERVER['PHP_AUTH_USER']) || strcmp ($_SERVER['PHP_AUTH_USER'],$user)!=0 ||
!isset (
$_SERVER['PHP_AUTH_PW']) || strcmp($_SERVER['PHP_AUTH_PW'],$pass)!=0 || !isset ($_SESSION['firstauthenticate']) || !$_SESSION['firstauthenticate']) {
$_SESSION['firstauthenticate']=true;
authenticate();
} else {
//我現在要銷毀 session 變數
session_unset();
//你的程式碼在下面
}
?>
11
marco dot moser at oltrefersina dot it
18 年前
我建議將使用者驗證和管理工作委託給網路伺服器 (透過 .htaccess, ...)。

1. 設定一個全域 /logon/ 目錄,其中包含一個限制存取的 .htaccess 檔案

2. 使用 fopen 包裝器

$hh = @fopen("http://{$_SERVER['PHP_AUTH_USER']}:{$_SERVER['PHP_AUTH_PW']}".
@{$_SERVER['SERVER_NAME']}/logon/", "r");
if (!$hh) authenticate(); // 通常的 header WWW-Authenticate ...
fclose($hh);
11
web at kwi dot dk
18 年前
雖然摘要式驗證仍然比基本式驗證優越得多,但必須記住一些安全問題。

在這方面,上面提供的摘要範例有些缺陷,因為 nonce 永遠不會逾時或失效。因此,它變成了一個等同於密碼的東西(雖然僅限於特定的 URL),竊聽者可以在未來的任何時間使用它來獲取頁面,從而允許攻擊者始終訪問該頁面的最新版本,或者(更糟糕的是)重複調用 CGI 腳本——例如,如果使用者請求 URL「/filemanager?delete=somefile」,攻擊者可以在未來的任何時間重複此刪除操作,可能是在該檔案被重新建立之後。

雖然可能無法在不重新驗證的情況下更改 GET 數據,但 cookies 和 POST 數據 *可以* 被更改。

為了防止第一個問題,可以讓 nonce 包含時間戳,並加入一個檢查以確保超過 30 分鐘的 nonce 會導致新的身份驗證請求。

為了解決第二個問題,需要生成一次性的 nonce——也就是說,所有使用特定 nonce 的後續請求都必須被拒絕。

一種方法是:當使用者請求諸如「deletefile」的操作時,在會話變數中儲存一個隨機生成的 nonce,發出一個帶有該 nonce 的 401 身份驗證挑戰,然後在接收到身份驗證時與儲存的值進行檢查(並清除會話變數)。

這樣一來,雖然可能的竊聽者接收到 nonce 並因此獲得執行該操作的能力,但他只能執行一次——而且使用者本來也要執行它。(只有使用者或攻擊者,但不能兩者都執行該操作,因此是安全的。)

當然,在某些時候,只能通過切換到 HTTPS / SSL / TLS 來提高安全性(例如,這是抵禦中間人攻擊的唯一方法)。您決定安全級別。
9
najprogramato at post dot sk
20 年前
不要使用純文字的 Apache 身份驗證。使用自己的腳本來生成與密碼相關的新 ID 會更好。Apache 身份驗證數據會發送到每個頁面,因此可能的錯誤是已知的。
10
Ollie L
14 年前
我嘗試了範例 7,一開始我無法讓它工作。我花了一段時間才發現,在某個環節中,可能是伺服器,在 realm 中加入了一個看似隨機的數字 - 因此 valid_result 變數沒有使用正確的 realm 計算。

為了解決這個或任何類似的問題,請對範例進行以下更改

在第 43 行附近(如果執行下一步後則為 44 行;)
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1, 'realm'=>1);

在第 24 行之前
$realm = $data['realm'];

這兩個步驟會取得用於身份驗證請求的實際 realm,並將其替換到「valid_response」查詢中。

希望這有幫助 :)
12
idbobby at rambler dot ru
14 年前
首先,抱歉我的英文不好。
另一個帶有登出解決方案的授權腳本。
在 meint_at_meint_dot_net 提供的腳本中(https://php.dev.org.tw/manual/en/features.http-auth.php#93859)使用了 rewrite_module。如果該模組有任何問題,並且對 Web 伺服器的管理權限受到限制(包括對使用 .htaccess 的限制),那麼您可以使用此解決方案。

index.php
---------

<?php

$auth_realm
= 'My realm';

require_once
'auth.php';

echo
"您已登入為 {$_SESSION['username']}<br>";
echo
'<p><a href="?action=logOut">登出</a></p>'

?>

auth.php
--------

<?php

$_user_
= 'test';
$_password_ = 'test';

session_start();

$url_action = (empty($_REQUEST['action'])) ? 'logIn' : $_REQUEST['action'];
$auth_realm = (isset($auth_realm)) ? $auth_realm : '';

if (isset(
$url_action)) {
if (
is_callable($url_action)) {
call_user_func($url_action);
} else {
echo
'函式不存在,請求終止';
};
};

function
logIn() {
global
$auth_realm;

if (!isset(
$_SESSION['username'])) {
if (!isset(
$_SESSION['login'])) {
$_SESSION['login'] = TRUE;
header('WWW-Authenticate: Basic realm="'.$auth_realm.'"');
header('HTTP/1.0 401 Unauthorized');
echo
'您必須輸入有效的登入和密碼';
echo
'<p><a href="?action=logOut">再試一次</a></p>';
exit;
} else {
$user = isset($_SERVER['PHP_AUTH_USER']) ? $_SERVER['PHP_AUTH_USER'] : '';
$password = isset($_SERVER['PHP_AUTH_PW']) ? $_SERVER['PHP_AUTH_PW'] : '';
$result = authenticate($user, $password);
if (
$result == 0) {
$_SESSION['username'] = $user;
} else {
session_unset($_SESSION['login']);
errMes($result);
echo
'<p><a href="">再試一次</a></p>';
exit;
};
};
};
}

function
authenticate($user, $password) {
global
$_user_;
global
$_password_;

if ((
$user == $_user_)&&($password == $_password_)) { return 0; }
else { return
1; };
}

function
errMes($errno) {
switch (
$errno) {
case
0:
break;
case
1:
echo
'您輸入的使用者名稱或密碼不正確';
break;
default:
echo
'未知的錯誤';
};
}

function
logOut() {

session_destroy();
if (isset(
$_SESSION['username'])) {
session_unset($_SESSION['username']);
echo
"您已成功登出<br>";
echo
'<p><a href="?action=logIn">登入</a></p>';
} else {
header("Location: ?action=logIn", TRUE, 301);
};
if (isset(
$_SESSION['login'])) { session_unset($_SESSION['login']); };
exit;
}

?>
9
rob at theblip dot com
20 年前
關於在 IIS 中使用 php cgi 4.3.4 進行 HTTP 驗證,還有一個步驟。我努力搜尋但沒有在其他地方找到此資訊,所以這裡分享一下。當使用 php CGI 進行 HTTP 驗證時,您需要執行以下操作

1. 在您的 php.ini 檔案中,設定「cgi.rfc2616_headers = 0」

2. 在「網站屬性」->「檔案/目錄安全」->「匿名存取」對話方塊中,勾選「匿名存取」核取方塊,並取消勾選任何其他核取方塊(即取消勾選「基本驗證」、「整合式 Windows 驗證」和「摘要式」如果已啟用)。按一下「確定」。

3. 在「自訂錯誤」中,選取「401;1」到「401;5」的範圍,然後按一下「設定為預設值」按鈕。

最後這個步驟至關重要,但沒有在任何地方記錄。如果您不這樣做,IIS 將會傳回自己花俏但無用的「您未經授權」頁面,而不是要求憑證的標頭。但是,如果您這樣做,瀏覽器將會正確地要求憑證,並在 $_SERVER['PHP_AUTH_*'] 元素中提供它們。
7
siberion at hotmail dot com
19 年前
我提出了另一種方法來解決瀏覽器快取 WWW 驗證憑證並產生登出問題的問題。雖然大多數瀏覽器都有某種清除此資訊的方法,但我更希望我的網站來處理這項任務,而不是依賴使用者的判斷。

即使使用 Lalit 建立隨機領域名稱的方法,仍然可以使用 Firefox 中的「上一頁」按鈕返回受保護的區域,因此該方法無效。這是我的解決方案

由於瀏覽器將憑證附加到特定的 URL,因此請使用虛擬路徑,其中路徑的某個元件實際上是 PHP 腳本,而其後的所有內容都是 URI 的一部分,例如

http://www.example.com/some_dir/login.php/auth/8f631b92/

透過為 URL 的最後一個元件選擇不同的數字,可以欺騙瀏覽器,使其認為它們正在處理完全不同的網站,從而再次提示使用者輸入憑證。

請注意,使用隨機、不受限制的數字仍然允許使用者按下「上一頁」按鈕返回頁面。您應該在伺服器端檔案或資料庫中追蹤此數字,並在每次成功登入時重新產生它,以便最後一個數字失效。使用無效的數字可能會導致 403 回應,或者,根據您當天的心情,可能會導致 302 重導向到一個令人討厭的網站。

在這種情況下從產生的頁面連結時應謹慎,因為相對連結將相對於虛擬且不存在的目錄,而不是真正的腳本目錄。

希望這對某些人有幫助。
7
s dot i dot g at gmx dot com
15 年前
<?php

// 嘗試模擬 cpanel 登出樣式
// 唯一不同之處在於重新登入時會清除使用者名稱和密碼欄位
// 已在 ff2 和 ie8 上測試過

session_start();

$username = "test";
$password = "test";

if(isset(
$_GET['logout']))
{
unset(
$_SESSION["login"]);
echo
"您已登出 ... ";
echo
"[<a href='" . $_SERVER['PHP_SELF'] . "'>登入</a>]";
exit;
}

if (!isset(
$_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) || !isset($_SESSION["login"]))
{
header("WWW-Authenticate: Basic realm=\"測試\"");
header("HTTP/1.0 401 Unauthorized");
$_SESSION["login"] = true;
echo
"您未經授權 ... ";
echo
"[<a href='" . $_SERVER['PHP_SELF'] . "'>登入</a>]";
exit;
}
else
{
if(
$_SERVER['PHP_AUTH_USER'] == $username && $_SERVER['PHP_AUTH_PW'] == $password)
{
echo
"您已登入 ... ";
echo
"[<a href='" . $_SERVER['PHP_SELF'] . "?logout'>登出</a>]";
}
else
{
unset(
$_SESSION["login"]);
header("Location: " . $_SERVER['PHP_SELF']);
}
}

// 內容在此

?>
7
steuber at aego dot de
20 年前
這個登出問題的解決方案相當不錯

只要告訴瀏覽器它已成功登入!
其運作方式如下
1. 使用者點擊登出按鈕
2. 腳本發送 401 標頭
3. 使用者「不」輸入密碼
4. 如果沒有輸入密碼,腳本會發送 200 標頭

因此,瀏覽器會將「沒有密碼」視為有效的密碼記住。

範例

<?php
if (
(!isset(
$_SERVER['PHP_AUTH_USER']))
||(
(
$_GET["login"]=="login")
&& !(
(
$_SERVER['PHP_AUTH_USER']=="validuser")
&& (
$_SERVER['PHP_AUTH_PW']=="validpass")
)
)
||(
(
$_GET["logout"]=="logout")
&& !(
$_SERVER['PHP_AUTH_PW']=="")
)
) {
Header("WWW-Authenticate: Basic realm=\"Realm\"");
Header("HTTP/1.0 401 Unauthorized");
echo
"尚未登出...<br>\n";
echo
"<a href=\"index.php?login=login\">登入</a>";
exit;
} else if (
$_SERVER['PHP_AUTH_PW']=="") {
echo
"已登出...<br>\n";
echo
"<a href=\"index.php?login=login\">登入</a>";
exit;
}
?>
3
patrick dot moire at socopa dot fr
4 年前
範例登入/登出腳本

login.php

<?php

// 初始化
if ($_COOKIE["SESSION"]=='') {
setcookie("SESSION", 'AUTH', 0,'/');

// 識別遺失 (逾時或登出)
} else if ($_SERVER['PHP_AUTH_USER']!='' && $_COOKIE["USER_SESSION"]=='') {
$_SERVER['PHP_AUTH_USER'] = '';
}

// 基礎識別控制
$ident = executeSQL("SELECT * FROM UTILISATEURS WHERE upper(IDENTIFIANT)=Upper('".$_SERVER['PHP_AUTH_USER']."')");
if (
$_SERVER['PHP_AUTH_USER']!='' && strtoupper($ident['IDENTIFIANT'])==strtoupper($_SERVER['PHP_AUTH_USER']) && $ident['MOT_DE_PASSE']==$_SERVER['PHP_AUTH_PW']) {
$user = $_SERVER['PHP_AUTH_USER'];
setcookie("USER_SESSION", $user, time()+300,'/'); // 5 分鐘!

// 密碼不正確:要求識別
} else {
setcookie("SESSION", '', 1,'/');
header('WWW-Authenticate: Basic realm="我的領域"');
header('HTTP/1.0 401 Unauthorized');
die;
}

?>
<html>
<body >

您好 <?php echo $ident['NOM'].' '.$ident['PRENOM']; ?>
<br>
<br>
<a href="http://logout.php">登出</a>
</body>
</html>

logout.php

<?php
setcookie
("USER_SESSION", '', 1,'/');
header('Location: http://login.php');
?>
4
Paul
21 年前
這是一個非常容易成功登出的方法。

<?php
if ( $realm == '' )
$realm = mt_rand( 1, 1000000000 );
header( 'WWW-Authenticate: Basic realm='.$realm );
?>

要讓使用者登出,只需變更 $realm 的值
-1
Whatabrain
18 年前
回到 CGI 模式的驗證問題... mcbethh 建議使用這個來在 PHP 中設定一個本機變數
RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization},L]

但它沒有用。我看不到該變數。我的解決方案相當迂迴,但它有效

RewriteEngine on
RewriteCond %{HTTP:Authorization} !^$
RewriteCond %{REQUEST_METHOD} =GET
RewriteCond %{QUERY_STRING} =""
RewriteRule ^page.php$ page.php?login=%{HTTP:Authorization}$1

如果沒有參數且為 GET 請求,這會導致 Auth 字串被添加到 URL。這會防止 POST 和參數列表被破壞。

然後,在 PHP 腳本中,我將 Auth 字串儲存為 session cookie。

因此,登入我的腳本的唯一方法是前往沒有參數的 URL。
To Top