web-dev-qa-db-ja.com

PHPセッション固定/ハイジャック

私はPHP Session Fixation &ハイジャックとこれらの問題を防ぐ方法についてもっと理解しようとしています。 Chris ShiflettのWebサイトで次の2つの記事を読んでいます。

ただし、物事を正しく理解しているかどうかはわかりません。

セッションの固定を防ぐには、session_regenerate_id(true)を呼び出すだけで十分です。誰かが正常にログインした後?私はそれを正しく理解していると思います。

また、セッションハイジャックを防ぐために、$ _ GETを介してURLで渡されるトークンの使用についても説明しています。これは正確にどのように行われますか?誰かがログインしてトークンを生成し、それをセッション変数に保存し、各ページでそのセッション変数を$ _GET変数の値と比較すると思いますか?

このトークンは、セッションごとまたはページのロードごとに1回だけ変更する必要がありますか?

また、URLに値を渡すことなくハイジャックを防ぐ良い方法ですか?これはかなり簡単です。

145
me2

わかりました、2つの別個の、しかし関連する問題があり、それぞれ異なる方法で処理されます。

セッション固定

これは、攻撃者がユーザーのセッションのセッション識別子を明示的に設定する場所です。通常、PHPでは、http://www.example.com/index...?session_name=sessionidのようなURLを与えることで行われます。攻撃者がURLをクライアントに渡すと、攻撃はセッションハイジャック攻撃と同じになります。

セッションの固定を防ぐには、いくつかの方法があります(すべてを行う)。

  • session.use_trans_sid = 0ファイルに php.ini を設定します。これにより、PHPにURLに識別子を含めず、識別子のURLを読み取らないように指示します。

  • session.use_only_cookies = 1ファイルに php.ini を設定します。これにより、PHPにセッション識別子を持つURLを使用しないように指示します。

  • セッションのステータスが変更されるたびに、セッションIDを再生成します。次のいずれかを意味します。

    • ユーザ認証
    • セッションに機密情報を保存する
    • セッションに関する変更
    • 等...

セッションハイジャック

これは、攻撃者がセッション識別子を取得し、あたかもそのユーザーであるかのようにリクエストを送信できる場所です。これは、攻撃者が識別子を持っているため、サーバーに関して有効なユーザーとほとんど区別できないことを意味します。

セッションハイジャックを直接防ぐことはできません。ただし、使用するのが非常に難しく、難しくするための手順を実行できます。

  • 強力なセッションハッシュ識別子を使用します: session.hash_function in php.ini。 PHP <5.3の場合、SHA1の場合はsession.hash_function = 1に設定します。 PHP> = 5.3の場合、session.hash_function = sha256またはsession.hash_function = sha512に設定します。

  • 強力なハッシュを送信: session.hash_bits_per_character in php.ini。これをsession.hash_bits_per_character = 5に設定します。これにより、クラッキングは難しくなりませんが、セッションIDを推測しようとすると違いが生じます。 IDは短くなりますが、より多くの文字を使用します。

  • session.entropy_fileファイルで session.entropy_length および php.ini を使用して追加のエントロピーを設定します。前者をsession.entropy_file = /dev/urandomに設定し、後者をエントロピーファイルから読み取るバイト数に設定します(例:session.entropy_length = 256)。

  • セッションの名前をデフォルトのPHPSESSIDから変更します。これは、session_startを呼び出す前に、最初のパラメーターとして独自の識別子名で session_name() を呼び出すことによって実現されます。

  • あなたが本当に偏執的な場合は、セッション名も回転させることができますが、これを変更するとすべてのセッションが自動的に無効になることに注意してください(たとえば、時間に依存するようにします)。しかし、ユースケースによっては、オプションになるかもしれません...

  • セッションIDを頻繁にローテーションします。 (実際にそのレベルのセキュリティが必要でない限り)すべてのリクエストを行うのではなく、ランダムな間隔でこれを行います。攻撃者がセッションをハイジャックした場合、攻撃者がセッションを長時間使用できないようにしたいので、これを頻繁に変更する必要があります。

  • セッションに $_SERVER['HTTP_USER_AGENT']のユーザーエージェント を含めます。基本的に、セッションが開始したら、$_SESSION['user_agent']のようなものに保存します。次に、後続の各要求で、一致することを確認します。これは偽造される可能性があるため、100%信頼できるわけではないことに注意してください。

  • $_SERVER['REMOTE_ADDR']のユーザーのIPアドレス をセッションに含めます。基本的に、セッションが開始したら、$_SESSION['remote_ip']のようなものに保存します。これは、ユーザーに複数のIPアドレスを使用する一部のISP(従来のAOLなど)から問題が発生する可能性があります。しかし、それを使用すると、はるかに安全になります。攻撃者がIPアドレスを偽造する唯一の方法は、実際のユーザーとあなたの間のある時点でネットワークを侵害することです。また、ネットワークを危険にさらすと、ハイジャック(MITM攻撃など)よりもはるかに悪い結果をもたらす可能性があります。

  • 頻繁にインクリメントおよび比較するトークンをセッションおよびブラウザ側に含めます。基本的に、リクエストごとにサーバー側で$_SESSION['counter']++を実行します。また、ブラウザー側のJSで何かをして、同じことを行います(ローカルストレージを使用)。次に、リクエストを送信するときに、トークンのナンスを取得し、そのナンスがサーバー上で同じであることを確認します。これを行うことにより、攻撃者は正確なカウンターを持っていないため、ハイジャックされたセッションを検出できるはずです。そうすれば、2つのシステムが同じカウントを送信し、1つが偽造されたことを知ることができます。これはすべてのアプリケーションで機能するわけではありませんが、問題に対処する1つの方法です。

2つのメモ

セッション固定とハイジャックの違いは、セッション識別子がどのように侵害されるかだけです。固定では、識別子は攻撃者が事前に知っている値に設定されます。ハイジャックでは、ユーザーから推測または盗難されます。それ以外の場合、識別子が侵害されると、2つの効果は同じになります。

セッションIDの再生成

session_regenerate_id を使用してセッション識別子を再生成するたびに、古いセッションを削除する必要があります。これは、コアセッションハンドラーで透過的に発生します。ただし、一部の session_set_save_handler()を使用するカスタムセッションハンドラー はこれを行わず、古いセッション識別子に対する攻撃に対してオープンです。カスタムセッションハンドラを使用している場合は、開いている識別子を追跡し、保存している識別子と異なる場合は、古い識別子の識別子を明示的に削除(または変更)することを確認してください。

デフォルトのセッションハンドラを使用すると、session_regenerate_id(true)を呼び出すだけで問題ありません。これにより、古いセッション情報が削除されます。古いIDは無効になり、攻撃者(または他の人)がそれを使用しようとすると、新しいセッションが作成されます。ただし、カスタムセッションハンドラーには注意してください。

セッションの破棄

セッションを破棄する場合(ログアウト時など)、必ず完全に破棄してください。これには、Cookieの設定解除が含まれます。 session_destroy を使用:

function destroySession() {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
    session_destroy();
}
216
ircmaxell

両方のセッション攻撃の目標は同じです。別のユーザーの正当なセッションへのアクセスを取得します。しかし、攻撃ベクトルは異なります。

  • Session Fixation攻撃 では、攻撃者はすでに有効なセッションにアクセスしており、被害者にこの特定の使用を強制しようとしますセッション。

  • Session Hijacking攻撃 では、攻撃者は被害者のセッションのIDを取得してセッションを使用しようとします。

どちらの攻撃でも、セッションIDはこれらの攻撃の対象となる機密データです。そのため、読み取りアクセス(セッションハイジャック)と書き込みアクセス(セッション固定)の両方で保護する必要があるのはセッションIDです。

この場合も、HTTPSを使用して機密データを保護する一般的な規則が適用されます。さらに、以下を実行する必要があります。

Session Fixation攻撃を防ぐには、次のことを確認してください。

セッションハイジャック攻撃を防ぐには、次のことを確認してください。

bothセッション攻撃を防ぐには、次のことを確認してください。

  • アプリケーションが開始したセッションのみを受け入れます。これを行うには、開始時にセッションをクライアント固有の情報でフィンガープリントします。 User-AgentIDを使用できますが、リクエスト間で変更される可能性のあるリモートIPアドレスやその他の情報は使用しないでください。
  • session_regenerate_id(true) を使用して認証試行(true成功時のみ)または特権の変更後にセッションIDを変更し、古いセッションを破棄します。 ($_SESSIONbeforeを使用してsession_write_closeの変更を保存してください。古いIDに関連付けられたセッションを保持する場合は、IDを再生成します。そうしないと、新しいIDのセッションのみが影響を受けます。それらの変更。)
  • 適切なセッション有効期限の実装を使用するには( 30分後にPHPセッションを期限切れにするにはどうすればよいですか? を参照してください)。
37
Gumbo

あなたが言及するトークンは「ナンス」です-一度使用される番号。必ずしも一度だけ使用する必要はありませんが、使用時間が長いほど、ナンスをキャプチャしてセッションをハイジャックするために使用できる可能性が高くなります。

ノンスのもう1つの欠点は、ノンスを使用し、同じフォームで複数の並列ウィンドウを許可するシステムを構築するのが非常に難しいことです。例えばユーザーはフォーラムで2つのウィンドウを開き、2つの投稿で作業を開始します。

window 'A' loads first and gets nonce 'P'
window 'B' loads second and gets nonce 'Q'

複数のウィンドウを追跡する方法がない場合は、ウィンドウB/Qのナンスを1つだけ保存します。ユーザーがウィンドウAから投稿を送信し、ナンス 'P'を渡すと、システムはP != Qとして投稿を拒否します。

6
Marc B

Shiflettの記事は読みませんでしたが、何か誤解していると思います。

デフォルトでは、PHPは、クライアントがCookieを受け入れない場合は常に、URLでセッショントークンを渡します。ほとんどの場合、セッショントークンはCookieとして保存されます。

つまり、URLにセッショントークンを挿入すると、PHPはそれを認識し、後で使用しようとします。セッション固定は、誰かがセッションを作成し、セッショントークンを含むURLを開いて同じセッションを共有するように他のユーザーをだますときに発生します。ユーザーが何らかの方法で認証された場合、悪意のあるユーザーは、認証されたセッショントークンを知っています。セッショントークンは異なる特権を持っている可能性があります。

Shiflettが説明していると思いますが、通常行うべきことは、ユーザーの特権が変更されるたびに異なるトークンを再生成することです。

2
Andrea

はい。ログイン時にセッションIDを再生成することで、セッションの固定を防ぐことができます。攻撃者が新しく認証されたセッションのCookie値を知らない場合、この方法。問題を完全に止めるもう1つのアプローチは、ランタイム構成にsession.use_only_cookies=Trueを設定することです。攻撃者は、別のドメインのコンテキストでCookieの値を設定できません。セッション固定は、Cookie値をGETまたはPOSTとして送信することに依存しています。

0
rook