web-dev-qa-db-ja.com

PHPを介したHTTP認証ログアウト

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

これを実現できる回避策はありますが、バグが発生したり、特定の状況/ブラウザーで動作しない可能性があるため、潜在的に危険です。だからこそ、私は正しいクリーンなソリューションを探しています。

149
Josef Sábl

む。 正しい方法は存在せず、ブラウザ間で一貫性のある方法もありません。

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

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

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

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

言い換えれば、ログインボックスを再び表示できる可能性があります@ Karsten のように)、しかし、ブラウザはあなたのリクエストを尊重する必要はありません-したがって、この(mis)機能に依存しすぎないでください。

102
Piskvor

Safariでうまく機能する方法。 FirefoxとOperaでも動作しますが、警告があります。

Location: http://[email protected]/

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

59
Kornel

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

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

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

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

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

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

46
Jonathan Hanson

回避策

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を返すパスに置き換えます。

26
Anton Mochalin

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

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

適切なヘッダーを送信して(ログインしていない場合)、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

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

13
Karsten

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

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

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

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

7
Vlad GURDIGA

私の問題の解決策は次のとおりです。このページの2番目の例で、関数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;
}
7
Pie86

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

4
Greg Hewgill

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

logout.php

<?php
header("Location: http://[email protected]/log.php");
?>

log.php

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

この方法では、警告が表示されず、セッションが終了します

2
Kevin

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

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

From:http://trac.edgewall.org/ticket/791#comment:1

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

2
hakre

.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、他のブラウザのように認証をクリアしません;)

インストール済みのブラウザーでテストし、閉じた後、各ブラウザーは再入力時に一貫して再認証を必要とするようです。

2
Dooley

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

これは、このような認証ではHTTPエラーコード「401」を使用して、資格情報が必要であることをブラウザーに伝えるためです。この時点で、ブラウザーはユーザーに詳細の入力を求めます。それ以降、ブラウザが閉じられるまで、それ以上プロンプトを表示せずに常に資格情報を送信します。

1
Alnitak

私がこれまでに見つけた最良の解決策は次のとおりです(疑似コードの一種で、$isLoggedInはhttp認証の疑似変数です):

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

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

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

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

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

1
Josef Sábl

PHP_AUTH_DIGESTまたはPHP_AUTH_USER AND PHP_AUTH_PW資格情報を消去する唯一の効果的な方法は、ヘッダーHTTP/1.1 401 Unauthorizedを呼び出すことです。

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

たぶん私はポイントを逃しています。

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

1
Toby Allen

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

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

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

<meta http-equiv="Refresh" content="0; url=https://logout:[email protected]/" />

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

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

0
johnwayne

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

0
symcbean