4

ログインメカニズムとしてBASIC認証でjetty 6.1.22を使用しています。Web アプリに初めてログインすると、ブラウザーはユーザー名とパスワードを要求します。

session.invalidate() を使用してログアウトしようとすると、セッションは無効になりますが、資格情報はキャッシュされます。つまり、セキュリティで保護された URL に接続しようとすると、別のセッション ID が表示されますが、ユーザー名とパスワードのダイアログは表示されません。

4

1 に答える 1

32

(この質問は古いと思いますが、他の人が答えを求めているかもしれません)

BASIC認証はあなたが求めているものを実際には許可しませんが、いくつかの「癖」を受け入れる気があるなら、あなたが望むものに少し似たものを得ることができます.

BASIC 認証には、この方法での制御を困難にする 2 つの側面があります。

  • ステートレスです
  • クライアントサイドです

これらの側面はどちらも機能ですが、BASIC 認証を Java セッションにリンクすることは困難です。そのため、別のログイン メカニズム (Java FORM ログインなど) が存在します。

BASIC 認証はステートレス
です。これは、クライアントがサーバー側で何が起こっているのかまったくわからないことを意味し、BASIC 認証資格情報のセットを Cookie にリンクする方法がまったくないことを意味します (これは主に Java セッションを制御するものです)。ブラウザーが停止することを決定するまで (通常は、ブラウザーが閉じられ、新しいブラウザー セッションが作成されたため)、ブラウザーはすべての
要求で ユーザー名とパスワードを送信するだけです。 ブラウザーは、サーバーが資格情報を使用して何をしているかを知りません。それらがもう必要かどうかはわかりません。また、サーバー側が「新しいセッション」が開始されたと判断した時期もわかりません。リクエストごとにそのユーザー名とパスワードを送信し続けるだけです。

BASIC 認証はクライアント側
ユーザー/パスワードのダイアログはクライアントによって処理されます。サーバーが言うのは、「要求した URL にはユーザー名とパスワードが必要です。このセキュリティ レルムには 'xyz' という名前を付けました」.
サーバーは、ユーザーが毎回パスワードを入力しているかどうか、またはクライアントがパスワードをキャッシュしているかどうかを認識していません。そこに本当にユーザーがいるかどうか、またはパスワードがファイルから引き出されたかどうかはわかりません。
サーバーができる唯一のことは、「この URL にアクセスする前に、ユーザーとパスワードを提供する必要があります」と言うだけです。

偽装する方法
基本的に、ブラウザーが古い資格情報を送信しているときにそれを検出 (つまり、知識に基づいた推測) し、"Please give me a user+password" 応答 (HTTP 401) を再度送信する必要があります。

これを行う最も簡単な方法は、ユーザーがそのセッションに初めてログインしたことを検出し、401応答コードを送信するフィルターをアプリケーションに設定することです。何かのようなもの:

    if(session.getAttribute("auth") == null)
    {
        response.setStatus(401);
        response.setHeader("WWW-Authenticate", "basic realm=\"Auth (" + session.getCreationTime() + ")\"" );
        session.setAttribute("auth", Boolean.TRUE);
        writer.println("Login Required");
        return;
    }

その例では、セッションの作成時間でレルムに名前を付けました (あまりきれいではありませんが、別の形式にした方がよいでしょう)。これは、セッションを無効にするたびにセキュリティ レルムの名前が変更されることを意味し、クライアントが混乱するのを防ぐのに役立ちます (1 つだけ与えたのに、なぜ同じレルムに対してユーザーとパスワードを再度要求するのでしょうか?) .
クライアントの応答にはレルム名が含まれないため、新しいレルム名はサーブレット コンテナを混乱させることはありません。

ただし、ユーザーが最初にログオンしたときにパスワードを 2 回要求されないようにするのが秘訣です。そして、箱から出してすぐに、このソリューションはそれを行います-コンテナがそれを要求するために1回、次にフィルターが要求するときにもう一度。

2 つのログイン ボックスを取得しないようにする方法 4 つのオプションがあります。

  1. すべてコードで実行します。
  2. セカンダリ セッション Cookie を使用して、ユーザーが初めてログインしているかどうかを確認します。
  3. ルート URL を保護しないでください (ただし、何もしないでください)。
  4. 1 つのページを除いてすべてのアプリを保護しないようにし、ユーザーがログインしていない場合はそのページにリダイレクトします。

コードで行う

独自のサーブレット/フィルター内ですべてのセキュリティを実行できて、サーブレット コンテナー (Jetty) からの助けが得られない場合は、それほど難しくありません。web.xml で BASIC 認証を無効にするだけで、すべてコードで実行できます。(かなりの作業があり、セキュリティ ホールを開いたままにしないようにする必要がありますが、概念的には非常に簡単です)
ほとんどの人はそれをしたくありません。

セカンダリ Cookie
ユーザーがアプリケーションにログインした後、ブラウザ セッションの終了時に有効期限が切れる Cookie (「認証済み」) を設定できます。この Cookie は、Java セッションではなくブラウザ セッションに関連付けられています。
Java セッションを無効にする場合、 「認証済み」 Cookieを無効にしないでください。 ユーザーが新しいJava セッション (つまり) にログインしても、まだ「認証済み」である場合は、既存のブラウザー セッションを再利用しており、おそらく既存の HTTP 認証資格情報を再利用していることがわかります。その場合、新しい資格情報を強制的に与えるというトリックを行います。
session.getAttribute("auth")==null401

保護されていないルート URL
ルート URL が保護されておらず、これがユーザーが常にログインする URL であることがわかっている場合は、その URL に「auth」/チェックを入れるだけ401で問題が解決します。ただし、誤ってセキュリティ ホールを開けないように注意してください。
この URL には、ユーザーを「実際の」アプリ (保護されている) にリダイレクトする以外の機能はありません。

保護された 1 つの URL 保護され
た 1 つの URL があります (例: "/login")。
「auth」/401フィルターと同様に、すべてのページ (ログイン以外) に別のフィルター (または同じフィルター内の追加コード) を設定して、request.getUserPrincipal()が設定されているかどうかを確認します。そうでない場合は、ユーザーを「/login」にリダイレクトします。

はるかに簡単な解決策BASIC 認証の
代わりに FORM ログイン方法を使用するだけです。この問題を解決するために設計されています。

于 2011-03-03T05:56:35.943 に答える