PHP経由のHTTP認証ログアウト


151

HTTP認証保護フォルダーからログアウトする正しい方法は何ですか?

これを実現できる回避策はありますが、バグが発生したり、特定の状況やブラウザで機能しない可能性があるため、潜在的に危険です。それが私が正確でクリーンな解決策を探している理由です。


ログアウトの目的を指定してください。これは強制ログアウト(ユーザー非アクティブ化)にする必要がありますか?ユーザーのシンプルなログアウト機能?他に何か?
Karsten、

6
これがなぜ重要かはわかりませんが、どちらの場合も当てはまります。アプリケーションの内部条件と通常のログアウトボタンに基づく非アクティブ化です。なぜそれが重要なのか説明してください。質問に直接編集します。
JosefSábl、2009年

2
「正しいクリーンなソリューション」は、ブラウザに独自のログアウトボタンがあり、クリックすると、ブラウザがAuthヘッダーの送信を停止するようにすることです。
DanMan 2012

1
Web開発者ツールバーにはそのような「ボタン」があります。
JosefSábl2012

Josefの発言:FirefoxのWeb開発ツールバー ->Miscellaneous -> Clear Private Data -> HTTP Authentication
Yarin

回答:


103

ムー。正しい方法は存在せず、ブラウザ間で一貫した方法ありません

これは、HTTP仕様(セクション15.6)に起因する問題です。

既存のHTTPクライアントとユーザーエージェントは、通常、認証情報を無期限に保持します。HTTP / 1.1。は、サーバーがクライアントにこれらのキャッシュされた資格情報を破棄するように指示する方法を提供しません。

一方、セクション10.4.2には次のように書かれています。

要求にすでに認証資格情報が含まれている場合、401応答は、それらの資格情報の認証が拒否されたことを示します。401応答に前の応答と同じチャレンジが含まれていて、ユーザーエージェントが少なくとも1回は認証を試みている場合、エンティティには関連する診断情報が含まれている可能性があるため、ユーザーには応答で指定されたエンティティを提示する必要があります(SHOULD)。

言い換えると、(@ Karstenが言うように)ログインボックスを再び表示できる可能性がありますが、ブラウザは要求受け入れる必要はありません。この(誤った)機能にあまり依存しないでください


9
これはRFCのバグです。W3Cは面倒すぎて修正できません。とても悲しい。
Erik Aronesty

@Jonathan Hansonが以下で提案したように、HTTP認証とともに追跡Cookieを使用できます。これは私にとって最良の方法です。
machineaddict 2013

61

Safariでうまく機能するメソッド。FirefoxとOperaでも機能しますが、警告が表示されます。

Location: http://logout@yourserver.example.com/

これは、以前のユーザー名を上書きして、新しいユーザー名でURLを開くようブラウザに指示します。


14
RFC 3986(URI:Generic Syntax)セクション3.2.1に従って。(ユーザー情報)の使用user:password@hostは非推奨です。のみを使用することhttp://logout@yourserver.example.com/はできませんし、ほとんどの場合に機能するはずです。
aef 2011

1
@andho:はい、リダイレクトです。あなたは、ステータス302でそれを使用する必要があります
Kornel

1
どうやら、PHPのhttpリダイレクトの代わりに、logout @ yourserver.example.comへの単純なリンク(このURLへの「切断」リンク)も機能します。
moala

4
注意:相対パスを使用したフォームの送信は、再ログイン(ログアウトプロンプトでログイン)した後で失敗する場合があります。これは、アドレスがyourserver.example.com/pathではなく、logout @ yourserver.example.com /
Jason

1
logout@yourserver.example.comは、Chromeでは問題を解決しますが、Firefoxではセキュリティの質問を表示します。logout:true@yourserver.example.comは、Firefoxのプロンプトをセキュリティの問題にしません。IE8での2つのURLの作業のどちら:/
トールA.ペダーセン

46

簡単な答えは、http-authenticationから確実にログアウトできないことです。

長い答え:(
他のHTTP仕様と同様に)Http-authはステートレスであることを意図しています。したがって、「ログイン」または「ログアウト」することは、実際には理にかなった概念ではありません。それを確認するより良い方法は、HTTPリクエストごとに(そして、ページのロードは通常複数のリクエストであることを覚えておいてください)、「リクエストしていることを実行することを許可されていますか?」です。サーバーは、各要求を新しいものとして認識し、以前の要求とは無関係です。

ブラウザーは、最初の401でユーザーに伝えた資格情報を記憶し、その後の要求に対するユーザーの明示的な許可なしに再送信することを選択しています。これは、ユーザーが期待する「ログイン/ログアウト」モデルをユーザーに提供しようとする試みですが、これは純粋に策略です。この状態の持続をシミュレートしているのはブラウザです。Webサーバーはそれを完全に認識していません。

したがって、「ログアウト」は、http-authのコンテキストでは、ブラウザによって提供される純粋なシミュレーションであり、サーバーの権限の範囲外です。

はい、クラッジがあります。しかし、それらはRESTful性(それがあなたにとって価値がある場合)を壊し、信頼性がありません。

サイト認証にログイン/ログアウトモデルが絶対に必要な場合、最善の策は、何らかの方法(mysql、sqlite、flatfileなど)でサーバーに保存された状態の永続性を備えた追跡Cookieです。これには、たとえばPHPですべてのリクエストを評価する必要があります。


26

回避策

JavaScriptを使用してこれを行うことができます。

<html><head>
<script type="text/javascript">
function logout() {
    var xmlhttp;
    if (window.XMLHttpRequest) {
          xmlhttp = new XMLHttpRequest();
    }
    // code for IE
    else if (window.ActiveXObject) {
      xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    if (window.ActiveXObject) {
      // IE clear HTTP Authentication
      document.execCommand("ClearAuthenticationCache");
      window.location.href='/where/to/redirect';
    } else {
        xmlhttp.open("GET", '/path/that/will/return/200/OK', true, "logout", "logout");
        xmlhttp.send("");
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4) {window.location.href='/where/to/redirect';}
        }


    }


    return false;
}
</script>
</head>
<body>
<a href="#" onclick="logout();">Log out</a>
</body>
</html>

上記で行われることは:

  • IEの場合 -認証キャッシュをクリアしてどこかにリダイレクトする

  • 他のブラウザーの場合 -「logout」ログイン名とパスワードを使用して、舞台裏でXMLHttpRequestを送信します。リクエストに200 OKを返すパスに送信する必要があります(つまり、HTTP認証は必要ありません)。

'/where/to/redirect'ログアウト後にリダイレクトするパスに置き換え、'/path/that/will/return/200/OK'200 OKを返すサイトのパスに置き換えます。


5
別のユーザーとしてログインすることは、ある程度の回避策です。しかし、これは実際に機能し、より多くの信用に値します。
CharlieRudenstål2013

2
これが最良の答えだと思います。同様の質問に対するこの回答で述べたように、パスワードをランダム化することにはいくつかの利点があるかもしれません。
zelanix 2014年

2
これは私が欲しかったものでした-すべてのブラウザで問題なく動作しました。引き継いだ「ログアウト」ページをそのまま引き継いだ。私は必ずしも(おそらく不合理に)JSを使用する必要はありませんでしたが、他のすべての回答にはブラウザー間の問題があり、これは完璧に機能しました。
dgig 2014年

説明されている方法でこの作業を行うことはできません。保護された領域に戻ると、ブラウザーは、ヘッダーで最後に使用された有効な資格情報を送信して、再度認証を行います。しかし、少し変更を加えるだけでうまくいきました。保護された領域と同じレルムのヘッダーを持つ200 OK応答を変更しましたが、「logout:logout」ユーザー/パスのみを受け入れます。このようにして、この「ログアウト」ユーザーでログインしたユーザーが、保護された領域に戻ったときに再試行するユーザーになります。保護された領域はこのユーザー/パスを拒否するため、ユーザーは資格情報を変更できます。
jonaguera 2015

2
説明のとおり、これは機能しません。クローム40とFirefox 35でテスト
funforums

13

回避策(クリーンではない(または機能している!コメントを参照)ソリューションではない):

彼の資格情報を一度無効にします。

適切なヘッダーを送信して(ログインしていない場合)、HTTP認証ロジックをPHPに移動できます。

Header('WWW-Authenticate: Basic realm="protected area"');
Header('HTTP/1.0 401 Unauthorized');

そして、入力を次のように解析します:

$_SERVER['PHP_AUTH_USER'] // httpauth-user
$_SERVER['PHP_AUTH_PW']   // httpauth-password

したがって、彼の資格情報を一度無効にすることは簡単です。


18
このソリューションの問題は、次のとおりです。資格情報がOKではないことをIEに知らせます。空のフィールドのあるログインダイアログが表示されます(パスワードマネージャーに保存されている値は表示されません)。ただし、[キャンセル]をクリックしてページを更新すると、保存されている資格情報が送信されるため、再度ログインできます。
JosefSábl、2009年

反対投票; Josef Sableがコメントしたように、これは目の前の問題を解決しません。
Chris Wesseling 2012年

7

2つのステップでのHTTP基本認証からのログアウト

「パスワード保護」という名前のHTTP基本認証レルムがあり、ボブがログインしているとします。ログアウトするには、2つのAJAXリクエストを作成します。

  1. スクリプト/ logout_step1にアクセスします。ランダムな一時ユーザーを.htusersに追加し、そのログインとパスワードで応答します。
  2. 一時的なユーザーのログインとパスワードで認証されたアクセススクリプト/ logout_step2 。スクリプトは一時ユーザーを削除し、応答に次のヘッダーを追加します。WWW-Authenticate: Basic realm="Password protected"

この時点で、ブラウザはボブの資格情報を忘れていました。


1
うわー!たとえそれが完全に骨の折れることであったとしても、これは全くの独創性のための+1に本当に値します。
Andy Triggs 2012

7

この問題に対する私の解決策は次のとおりです。あなたは機能を見つけることができhttp_digest_parse$realmかつ$users、このページの第二の例では:http://php.net/manual/en/features.http-auth.php

session_start();

function LogOut() {
  session_destroy();
  session_unset($_SESSION['session_id']);
  session_unset($_SESSION['logged']);

  header("Location: /", TRUE, 301);   
}

function Login(){

  global $realm;

  if (empty($_SESSION['session_id'])) {
    session_regenerate_id();
    $_SESSION['session_id'] = session_id();
  }

  if (!IsAuthenticated()) {  
    header('HTTP/1.1 401 Unauthorized');
    header('WWW-Authenticate: Digest realm="'.$realm.
   '",qop="auth",nonce="'.$_SESSION['session_id'].'",opaque="'.md5($realm).'"');
    $_SESSION['logged'] = False;
    die('Access denied.');
  }
  $_SESSION['logged'] = True;  
}

function IsAuthenticated(){
  global $realm;
  global $users;


  if  (empty($_SERVER['PHP_AUTH_DIGEST']))
      return False;

  // check PHP_AUTH_DIGEST
  if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
     !isset($users[$data['username']]))
     return False;// invalid username


  $A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
  $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);

  // Give session id instead of data['nonce']
  $valid_response =   md5($A1.':'.$_SESSION['session_id'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);

  if ($data['response'] != $valid_response)
    return False;

  return True;
}

4

通常、ブラウザーがユーザーに資格情報を要求し、それらを特定のWebサイトに提供すると、それ以上のプロンプトは表示されずに続行されます。クライアント側でCookieをクリアするさまざまな方法とは異なり、ブラウザーに提供された認証資格情報を忘れるように要求する同様の方法は知りません。


Firefoxで[プライベートデータの削除]を選択すると、認証されたセッションを削除するオプションがあると思います
Kristian J.

1
また、Firefox用のWeb開発者ツールバー拡張機能は、HTTP認証を削除する機能を提供します。私たちは本当に、ダウンロードFFの拡張にユーザーの皆様に尋ねるか、不可解なブラウザコマンドを実行することはできませんよう:-)しかし、これは問題外です
ヨーゼフSABL

2
FirefoxのHTTP認証からのデフォルトのログアウト方法は、[ツール]> [最近の履歴をクリア...]の[アクティブなログイン]チェックボックスとして利用できます。これは直感的ではなく、1つのドメインからのみログアウトすることもできません。常にすべてのページからログアウトします。
aef 2011

2

Trac-デフォルトでは-HTTP認証も使用します。ログアウトは機能せず、修正できません:

  • これはHTTP認証スキーム自体の問題であり、Tracで適切に修正するためにできることは何もありません。
  • 現在、すべての主要なブラウザーで動作する回避策(JavaScriptまたはその他)はありません。

差出人: http : //trac.edgewall.org/ticket/791#comment : 103

質問に対する有効な回答はないようです。その問題は7年前に報告されており、完全に理にかなっています。HTTPはステートレスです。リクエストは認証資格情報で行われるかどうか。しかし、それはサーバーが要求を受け取るのではなく、クライアントが要求を送信することの問題です。サーバーは、リクエストURIが承認を必要とするかどうかのみを伝えることができます。


2

.htaccess認証をリセットする必要があったので、これを使用しました:

<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
    header('WWW-Authenticate: Basic realm="My Realm"');
    header('HTTP/1.0 401 Unauthorized');
    echo 'Text to send if user hits Cancel button';
    exit;
}
?>

ここで見つかりました:http : //php.net/manual/en/features.http-auth.php

図を行きます。

そのページにはいくつかのソリューションがあり、下部にも記されています。Lynxは他のブラウザーのように認証をクリアしません;)

インストールしたブラウザでテストしましたが、いったん閉じると、各ブラウザは常に再入時に再認証を必要とするようです。


これは機能していないようです。ポップアップログインボックスのないキャンセルテキストが表示されます。
Michael

結局のところ、これを送信するとWWW-Authenticate問題が発生し、自動的にログアウトされました。
Michael

逆に、あるブラウザー(Chrome)で問題を修正しているときにを送信しないWWW-Authenticateと、別のブラウザー(Firefox)が資格情報を記憶し、次のリクエストでそれらを送信して、自動的に再ログインするようになります。ああ!
Michael

次に、UAを見て、どちらかを実行すると解決策のように見えます
Lennart Rolland '21

2

これは探していた解決策ではないかもしれませんが、私はこのように解決しました。ログアウトプロセス用の2つのスクリプトがあります。

logout.php

<?php
header("Location: http://.@domain.com/log.php");
?>

log.php

<?php
header("location: https://google.com");
?>

このようにして警告が表示されず、セッションが終了します


1
これは私にとって本当に効果的な唯一の解決策でした!Firefox 37およびChromium 41でテスト済み
zesaver '11年

1

私の知る限り、htaccess(つまりHTTPベースの)認証を使用するときに「ログアウト」機能を実装するための明確な方法はありません。

これは、このような認証ではHTTPエラーコード '401'を使用して、資格情報が必要であることをブラウザーに通知し、その時点でブラウザーがユーザーに詳細を要求するためです。それ以降、ブラウザーが閉じられるまで、ブラウザーは常にプロンプ​​トを出さずに資格情報を送信します。


1

これまでに見つけた最善の解決策は$isLoggedIn次のとおりです(これは一種の疑似コードで、http authの疑似変数です)。

「ログアウト」時に、ユーザーが実際にログアウトしたことを示す情報をセッションに保存するだけです。

function logout()
{
  //$isLoggedIn = false; //This does not work (point of this question)
  $_SESSION['logout'] = true;
}

認証を確認する場所で、条件を展開します。

function isLoggedIn()
{
  return $isLoggedIn && !$_SESSION['logout'];
}

セッションはhttp認証の状態にいくらかリンクされているため、ユーザーはブラウザーを開いたままで、ブラウザーでhttp認証が持続している限り、ログアウトしたままになります。


4
HTTP基本認証はRESTfulですが、セッションはそうではありません。
デーモン

1

多分私はポイントを逃しています。

HTTP認証を終了するために私が見つけた最も信頼できる方法は、ブラウザーとすべてのブラウザーウィンドウを閉じることです。JavaScriptを使用してブラウザウィンドウを閉じることはできますが、すべてのブラウザウィンドウを閉じることはできないと思います。


FYI一部のブラウザではないだろう近くのウィンドウが開いてタブのみですので、ポイントは本当に議論の余地がある場合
スケープ

何年も前のことですが、ウィンドウを閉じずにログアウトボタンを実装する必要がありました:-)しかし、「ウィンドウを閉じない」ことについては考えないでしょう。しかし、ねえ、これは誰かのために働くかもしれない単純な解決策であり、私は正直に言うとそれを逃しました。
JosefSábl2017年

1

私は一掃することがわかってきた唯一の効果的な方法PHP_AUTH_DIGESTPHP_AUTH_USERPHP_AUTH_PW資格情報は、ヘッダを呼び出すことですHTTP/1.1 401 Unauthorized

function clear_admin_access(){
    header('HTTP/1.1 401 Unauthorized');
    die('Admin access turned off');
}

0

他の人は基本的なhttp認証からログアウトすることは不可能であると言っていますが、同様に動作する認証を実装する方法があります。明らかなアプローチの1つは、auth_memcookieを使用することです。これを使用して基本的なHTTP認証を実装する場合(つまり、HTTPフォームではなくブラウザダイアログを使用してログインする場合)、認証を、ユーザーが後に来た場所にリダイレクトするPHPスクリプトを含む別の.htaccess保護ディレクトリに設定しますmemcacheセッションの作成。


0

ここにはたくさんの素晴らしい-複雑な-答えがあります。私の特定のケースでは、ログアウトのためのクリーンでシンプルな修正を見つけました。まだEdgeでテストしていません。ログインしたページに、次のようなログアウトリンクを配置しました。

<a href="https://MyDomainHere.net/logout.html">logout</a>

そして、そのlogout.htmlページ(これも.htaccessによって保護されています)の先頭に、次のようなページ更新があります。

<meta http-equiv="Refresh" content="0; url=https://logout:logout@MyDomainHere.net/" />

「ログアウト」という単語をそのまま残して、サイトにキャッシュされたユーザー名とパスワードをクリアする場所。

最初から複数のページに直接ログインできるようにする必要がある場合は、それらのエントリポイントごとに、対応するlogout.htmlページが必要になることを認めます。それ以外の場合は、実際のログインプロンプトの前にプロセスに追加のゲートキーパーステップを導入することでログアウトを集中化でき、ログインの宛先に到達するにはフレーズの入力が必要になります。


1
前進すると、これは機能し、ログアウトしますが、ブラウザのバックヒストリは引き続きセッションを再確立できます。
ジョンウェイン2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.