PHPセッションの修正/ハイジャック


145

PHP セッションの修正とハイジャック、およびこれらの問題を防ぐ方法について、もっと理解しようとしています。Chris ShiflettのWebサイトで次の2つの記事を読んでいます。

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

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

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

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

また、URLで値を渡さなくてもハイジャックを防止できる優れた方法ですか?これはかなり簡単になります。


たぶん、これらの推奨事項を見つけたページへのリンクを追加できます。
ガンボ

回答:


219

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

セッション固定

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

セッションの固定を防ぐ方法はいくつかあります(それらすべてを実行してください)。

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

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

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

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

セッションハイジャック

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

セッションハイジャックを直接防止することはできません。ただし、ステップを入れて、使用を非常に困難かつ困難にすることができます。

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

  • 強力なハッシュを送信session.hash_bits_per_characterphp.iniます。これをに設定しsession.hash_bits_per_character = 5ます。これによってクラックが難しくなることはありませんが、攻撃者がセッション識別子を推測しようとするときに違いが出ます。IDは短くなりますが、より多くの文字を使用します。

  • 追加のエントロピーを設定session.entropy_fileし、session.entropy_length自分の中php.iniのファイル。前者をsession.entropy_file = /dev/urandomに、後者をエントロピーファイルから読み取るバイト数に設定しますsession.entropy_length = 256

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

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

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

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

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

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

二つについてのメモ

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

セッションIDの再生成

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

デフォルトのセッションハンドラーを使用すると、を呼び出すだけで問題ありません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();
}

4
文字ごとに4ビットではなく5を使用しても、「強度」は変更されません(この場合、「強度」が意味するものは何でも)。しかし、あなたのポイントは一般的には賢明ですが、いくつかの重要な詳細が欠けています。たとえば、古いセッションIDに関連付けられているセッションがどうなるか、または無効になった後に古いセッションIDを持つセッションをどのように処理するかなどです。
ガンボ

2
@battal:いいえ、それがポイントです。session_regenerate_id古いIDにまだ関連付けられているセッションは無効になりません。delete_old_sessionパラメータがtrueに設定されている場合のみ、セッションが破棄されます。しかし、攻撃者がこのIDの再生成を開始した場合はどうなりますか?
ガンボ

6
セッション変数を変更するたびにセッションを再生成することに同意しません。これは、ログイン/ログアウト時にのみ行う必要があります。また、ユーザーエージェントのチェックは意味がなく、REMOTE_ADDRのチェックには問題があります。追加したいことの1つはsession.entropy_file = /dev/urandomです。PHPの内部エントロピー生成は非常に弱いことが証明されており、/ dev / randomまたは/ dev / uranomによって提供されるエントロピープールは、ハードウェアrngなしでWebサーバーで取得できる最高のものです。
2011

4
また、session.cookie_httponlyおよびを追加する必要がありsession.cookie_secureます。最初のものは、xssを阻止するのに役立ちます(ただし、完全ではありません)。第二は... OWASP A9を停止するための最良の方法です
ルーク

4
そのような素晴らしい答えは理解できませんが、最も重要な部分が欠けています。SSL/ HTTPSを使用してください。カウンターの増分は、複数のリクエストが次々と速くなる、ユーザーがページを2回更新する、または送信ボタンを2回押すという問題の原因です。現在、IPアドレスソリューションは、すべてのモバイルユーザーと常に変化するIPの問題です。IPの最初のセットを見ることができますが、それでも問題が発生します。SSL / HTTPSを使用しており、そもそもセッションIDの検出を防ぐことが最善です。
サンネ2013

37

どちらのセッション攻撃にも同じ目的があります。別のユーザーの正当なセッションにアクセスすることです。ただし、攻撃ベクトルは異なります。

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

  • では、セッションハイジャック攻撃は、攻撃者が彼/彼女のセッションを使用して、被害者のセッションのIDを取得しようとします。

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

この場合も、HTTPSを使用して機密データを保護するという一般的なルールが適用されます。さらに、次のことを行う必要があります。

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

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

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

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

素晴らしい投稿、特に最後のセクション。
マティス

6

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

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

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

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


では、これはセッションの固定とどう関係しているのでしょうか?
2011

2
彼は、特に多くのAJAXリクエストを同時に使用する領域で有効なポイントを持っています。
DanielG

2

私はシフレットの記事を読んでいませんが、あなたは何かを誤解していると思います。

デフォルトでは、クライアントがCookieを受け入れない場合は常に、PHPはセッショントークンをURLで渡します。そうでなければ、最も一般的なケースでは、セッショントークンはcookieとして保存されます。

これは、URLにセッショントークンを配置すると、PHPがそれを認識し、その後それを使用しようとすることを意味します。セッションの固定は、誰かがセッションを作成し、別のユーザーをだまして、セッショントークンを含むURLを開いて同じセッションを共有させるときに発生します。ユーザーが何らかの方法で認証された場合、悪意のあるユーザーは、認証されたセッショントークンを知っています。

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


これを追加するには、既存のユーザー権限で引き続き有効であるため、以前に開いたセッションを破棄するようにしてください。
corrodedmonkee

0

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.