セッションの乗っ取りを防ぐ最善の方法は何ですか?


124

特に、これは、クライアントセッションCookieを使用してサーバー上のセッションを識別する場合に関係します。

Webサイト全体にSSL / HTTPS暗号化を使用する最良の答えはありますか?中間の攻撃者が既存のクライアントセッションCookieを盗聴することができないという最高の保証がありますか?

そして、おそらくセッションCookieに格納されているセッション値自体にある種の暗号化を使用するのに2番目に適していますか?

悪意のあるユーザーがマシンに物理的にアクセスできる場合でも、ファイルシステムを調べて有効なセッションCookieを取得し、それを使用してセッションを乗っ取ることができますか?

回答:


140

セッション値を暗号化しても効果はありません。セッションCookieはすでに任意の値です。暗号化すると、盗聴可能な別の任意の値が生成されます。

唯一の実際のソリューションはHTTPSです。サイト全体でSSLを実行したくない場合(おそらくパフォーマンスの懸念がある場合)、機密領域を保護しているSSLのみで問題を回避できる可能性があります。これを行うには、まずログインページがHTTPSであることを確認します。ユーザーがログインするとき、通常のセッションCookieに加えて、安全なCookieを設定します(つまり、ブラウザーはSSLリンク経由でのみ送信します)。次に、ユーザーが「機密」領域の1つにアクセスしたときに、それらをHTTPSにリダイレクトし、その安全なCookieの存在を確認します。実際のユーザーにはそれがありますが、セッションハイジャッカーにはありません。

編集:この回答はもともと2008年に書かれました。現在は2016年であり、サイト全体でSSLを使用しない理由はありません。平文HTTPはもうありません!


28
HTTPSは盗聴のみを防止します。ただし、XSSがある場合、またはセッションIDが簡単に推測できる場合、またはセッションの修正に脆弱な場合、またはセッションIDのストレージが弱い場合(SQLインジェクション?)、SSLはまったく改善されません。
Calimo、2012年

5
@Josh悪意のあるユーザーがマシンに物理的にアクセスできる場合でも、ファイルシステムを調べて有効なセッションCookieを取得し、それを使用してセッションを乗っ取ることができますか?
パセリエ

72
悪意のあるユーザーがファイルシステムに物理的にアクセスできる場合、セッションをハイジャックする必要はありません。
Josh Hinman

25
@ジョシュ。事実ではありませんが、ファイルシステムへの物理的なアクセスが制限されている場合があります。同僚がトイレに急いでロックを解除したままになっているラップトップを想像してください。今必要なのは、そのラップトップに行ってEditThisCookieプラグインをインストールし、EditThisCookieエクスポート機能を使用してplus.google.comで彼のCookieを取得するだけです。所要時間:18秒。
Pacerier

1
私はGoogleがビルドで、これは明らかにあなたは、セッションハイジャックの話をするときの思うだろう最初のものであるとして、セキュリティ機能のいくつかの種類がありますかなり確信している
xorinzor

42

SSLはスニッフィング攻撃にのみ役立ちます。攻撃者があなたのマシンにアクセスできる場合、私は彼らがあなたの安全なクッキーもコピーできると思います。

少なくとも、古いCookieがしばらくすると値を失うことを確認してください。cookieが機能しなくなると、成功したhijaking攻撃でさえ阻止されます。ユーザーが1か月以上前にログインしたセッションからのCookieを持っている場合は、パスワードを再入力してもらいます。ユーザーがサイトの「ログアウト」リンクをクリックするたびに、古いセッションのUUIDが二度と使用できないようにしてください。

このアイデアが機能するかどうかはわかりませんが、次のようになります:セッションCookieにシリアル番号を追加します。

SessionUUID、シリアル番号、現在の日付/時刻

この文字列を暗号化して、セッションCookieとして使用します。シリアル番号を定期的に変更します-おそらくCookieが5分経過した後、Cookieを再発行します。必要に応じて、すべてのページビューで再発行することもできます。サーバー側では、そのセッションに対して発行した最後のシリアル番号の記録を保管してください。誰かが間違ったシリアル番号のCookieを送信した場合、攻撃者は以前に傍受したCookieを使用している可能性があるため、セッションUUIDを無効にし、ユーザーにパスワードを再入力して新しいCookieを再発行するよう依頼します。

ユーザーが複数のコンピュータを使用している可能性があるため、アクティブなセッションが複数存在する可能性があることに注意してください。コンピュータを切り替えるたびにログインを強制されるようなことをしないでください。


私はこれが古い投稿であることを知っていますが、攻撃者が「シリアル番号」によって割り当てられたウィンドウ内でセッションをハイジャックしても、それは彼に影響を与えないことを含めたかっただけです。
2013

@crush、しかしその後、攻撃者は割り当てられたウィンドウの後にロックアウトされますよね?したがって、少なくとも攻撃ウィンドウは小さくなります。
Johanneke 2013

2
唯一の問題は、ユーザーが5分間ウェブサイトを離れた場合、再度ログインする必要があることです
elipoultorak

21

PHPのセキュリティに関する本を読むことを検討しましたか?強くお勧めします。

SSL認定されていないサイトでは、次の方法で大成功しました。

  1. 同じアカウントで複数のセッションを許可しないでください。IPアドレスだけでこれをチェックしていないことを確認してください。むしろ、データベースにユーザーセッションと共に保存されているログイン時に生成されたトークン、およびIPアドレス、HTTP_USER_AGENTなどでチェックします。

  2. 関係ベースのハイパーリンクを使用してリンクを生成します(例:http: //example.com/secure.php?token=2349df98sdf98a9asdf8fas98df8)リンクには、ランダムに生成されたページリダイレクト時に、x-BYTE(推奨サイズ)ランダムソルトMD5文字列が追加されますトークンは要求されたページに対応します。

    • リロード時に、いくつかのチェックが行われます。
    • 発信元IPアドレス
    • HTTP_USER_AGENT
    • セッショントークン
    • あなたはポイントを取得します。
  3. 短寿命のセッション認証Cookie。上記のように、セッションの有効性への直接参照の1つである安全な文字列を含むCookieは良い考えです。x分ごとに期限切れにし、そのトークンを再発行して、セッションを新しいデータと再同期します。データに不一致がある場合は、ユーザーをログアウトさせるか、セッションを再認証してもらいます。

私はこのテーマの専門家ではありません。この特定のトピックについて少し経験がありました。これのいくつかがそこにいる人を助けることを願っています。


4
おすすめの本はありますか?
Rikki

1
特に、OPがPHPについて特に何も述べていないことを考えると、一般的なセキュリティブックだけを見るほうがよいと言えます(特に、異なる言語間のセキュリティは実装の詳細のみが異なりますが、概念は同じです)。
matts1 2014年

2017年には、facebook / gmailなどでも、ユーザーを嫌がらない限り、同じアカウントで(特にモバイルデバイスを使用して)複数のセッションを許可しています。#1は少し時代遅れです。
カウバート

20
// Collect this information on every request
$aip = $_SERVER['REMOTE_ADDR'];
$bip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$agent = $_SERVER['HTTP_USER_AGENT'];
session_start();

// Do this each time the user successfully logs in.
$_SESSION['ident'] = hash("sha256", $aip . $bip . $agent);

// Do this every time the client makes a request to the server, after authenticating
$ident = hash("sha256", $aip . $bip . $agent);
if ($ident != $_SESSION['ident'])
{
    end_session();
    header("Location: login.php");
    // add some fancy pants GET/POST var headers for login.php, that lets you
    // know in the login page to notify the user of why they're being challenged
    // for login again, etc.
}

これが行うことは、ユーザーのセッションに関する「コンテキスト」情報をキャプチャすることです。これは、単一のセッションの存続期間中に変更してはならない情報です。ユーザーは、米国と中国のコンピューターを同時に利用することはないでしょう。したがって、同じセッション内でIPアドレスが突然変化してセッションハイジャックの試みが強く示唆される場合は、セッションを終了してユーザーに再認証を強制することにより、セッションを保護します。これによりハッキングの試みが阻止され、攻撃者はセッションにアクセスする代わりにログインを強制されます。試行(少しそれをajaxにしてください)とユーザーを通知します。少しイライラ+通知されたユーザーとそのセッション/情報は保護されます。

ユーザーエージェントとX-FORWARDED-FORを投入して、プロキシ/ネットワークの背後にあるシステムのセッションの一意性をキャプチャするために最善を尽くします。あなたはそれより多くの情報を使うことができるかもしれません、自由に創造的になってください。

それは100%ではありませんが、かなり効果的です。

ユーザーがウェブサイトを離れて戻ってきたときにセッションを保護し、セッションを期限切れにするためにできることは他にもあります。空白のHTTP_REFERER(ドメインがURLバーに入力された)をキャプチャすることで、ユーザーが離脱したり戻ったりすることを検出したり、HTTP_REFERERの値がドメインと等しいかどうかを確認したりできます(ユーザーが外部リンクまたは細工されたリンクをクリックして、地点)。

セッションを期限切れにします。無期限に有効なままにしないでください。

Cookieに依存しないでください。Cookieが盗まれる可能性があります。これは、セッションハイジャック攻撃のベクトルの1つです。


3
特定の(かなり大きいが、技術的には後方の)ISPがユーザーの接続の再ルーティングに基づいてユーザーのブラウザーのIPを時々変更するという状況に遭遇しました。これにより、REMOTE_ADDRチェックが偽陰性を返しました。
goofballLogic 2015

なぜハッシュを作成するのですか?$_SESSION['ident'] = $aip . $bip . $agent;同様に安全です。
Dan Bray

2
外出先でWebサイトを使用し、あるアクセスポイントから別のアクセスポイントに移動するモバイルユーザーがいる場合、IPは変化し続け、アカウントからサインアウトされ続けます。
カリーム2017年

プロキシとVPNはどうですか?TORプロキシを使用しているユーザーは、常に自分のアカウントからログアウトされます。実際には数分ごとにログアウトされます。
Bradley

見落としがあったとしても、IPアドレスはクライアントによって操作される可能性があるので、攻撃者をとにかく阻止することはあまりありません。
Bradley

9

これに記載されているセキュアCookieプロトコルを試してくださいLiu、Kovacs、Huang、Goudaによるペーパーで。

ドキュメントに記載されているように:

クライアントとサーバー間で実行される安全なCookieプロトコルは、認証、機密性、完全性、およびリプレイ防止の4つのサービスを提供する必要があります。

導入の容易さに関しては:

効率の点では、このプロトコルにはデータベースの検索や公開鍵の暗号化は含まれていません。配備の面では、このプロトコルは既存のWebサーバーに簡単に配備でき、インターネットCookieの仕様を変更する必要はありません。

簡単に言えば、それは安全で軽量であり、私にとってはとてもうまくいきます。


9
リンクはプロトコルの仕様です-実装へのリンクはありますか?それは素晴らしいことです-ありがとう。
アダム

9

セッションのハイジャックを100%防ぐ方法はありませんが、攻撃者がセッションをハイジャックする時間を短縮する方法があります。

セッションのハイジャックを防ぐ方法:

1-常にSSL証明書でセッションを使用します。

2-httponlyをtrueに設定してのみセッションCookieを送信します(JavaScriptがセッションCookieにアクセスできないようにします)

2-ログインおよびログアウト時にセッション再生成IDを使用します(注:連続するajaxリクエストがある場合、複数のセッションを作成する可能性があるため、各リクエストでセッション再生成を使用しないでください。)

3-セッションタイムアウトを設定する

4-$ _SESSION変数にブラウザーのユーザーエージェントを格納し、各リクエストで$ _SERVER ['HTTP_USER_AGENT']と比較します。

5-トークンCookieを設定し、そのCookieの有効期限を0に設定します(ブラウザーが閉じられるまで)。各リクエストのCookie値を再生成します(ajaxリクエストの場合、トークンCookieを再生成しないでください)。例:

    //set a token cookie if one not exist
    if(!isset($_COOKIE['user_token'])){
                    //generate a random string for cookie value
        $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

        //set a session variable with that random string
        $_SESSION['user_token'] = $cookie_token;
        //set cookie with rand value
        setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
    }

    //set a sesison variable with request of www.example.com
    if(!isset($_SESSION['request'])){
        $_SESSION['request'] = -1;
    }
    //increment $_SESSION['request'] with 1 for each request at www.example.com
    $_SESSION['request']++;

    //verify if $_SESSION['user_token'] it's equal with $_COOKIE['user_token'] only for $_SESSION['request'] > 0
    if($_SESSION['request'] > 0){

        // if it's equal then regenerete value of token cookie if not then destroy_session
        if($_SESSION['user_token'] === $_COOKIE['user_token']){
            $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

            $_SESSION['user_token'] = $cookie_token;

            setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
        }else{
            //code for session_destroy
        }

    }

            //prevent session hijaking with browser user agent
    if(!isset($_SESSION['user_agent'])){
        $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
    }

    if($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']){
      die('session hijaking - user agent');
    }

注:ajaxリクエストでトークンCookieを再生成しないでください注:上記のコードは例です。注:ユーザーがログアウトする場合、Cookieトークンとセッションを破棄する必要があります

6-一部のユーザーはリクエストごとにIPを変更するため、セッションIPのハイジャックを防ぐためにユーザーIPを使用するのは良い方法ではありません。有効なユーザーに影響する

7-個人的にセッションデータをデータベースに保存します。どの方法を採用するかはあなた次第です

私のアプローチに誤りを見つけた場合は修正してください。セッションのハイジャックを防ぐ方法が他にもある場合は、教えてください。


こんにちは、私はセッションの乗っ取り(ASP.NETで)を防止しようとしていて、上記のすべての手順を検討しました。おおよその動作ですが、ブラウザのInPrivateBrowsing /シークレットモードを使用すると、セッションがハイジャックされます。sessionId文字列に追加することを提案できますか?
Vishwanath Mishra 14

4

セッションIDには増分整数を使用しないでください。GUIDまたはその他のランダムに生成された長い文字列を使用する方がはるかに優れています。


3

セッションハイジャックに対する保護を作成するには多くの方法がありますが、それらはすべてユーザーの満足度を低下させるか、安全ではありません。

  • IPおよび/またはX-FORWARDED-FORチェック。これらは動作し、かなり安全です...しかし、ユーザーの苦痛を想像してみてください。彼らはWiFiを使ってオフィスに来て、新しいIPアドレスを取得してセッションを失います。再度ログインしました。

  • ユーザーエージェントチェック。上記と同様に、新しいバージョンのブラウザーがリリースされ、セッションが失われます。さらに、これらは「ハッキング」するのが本当に簡単です。ハッカーが偽のUA文字列を送信するのは簡単です。

  • localStorageトークン。ログオン時にトークンを生成し、それをブラウザーのストレージに保管して、暗号化されたCookie(サーバー側で暗号化)に保管します。これにはユーザーへの副作用はありません(localStorageはブラウザーのアップグレード後も存続します)。それはそれほど安全ではありません-それはあいまいさによる単なるセキュリティです。さらに、JSにいくつかのロジック(暗号化/復号化)を追加して、さらに不明瞭にすることができます。

  • Cookieの再発行。これはおそらく正しい方法です。トリックは、一度に1つのクライアントのみがCookieを使用できるようにすることです。したがって、アクティブユーザーはCookieを1時間以内に再発行します。新しいCookieが発行されると、古いCookieは無効になります。ハッキングは依然として可能ですが、行うのははるかに困難です。ハッカーまたは有効なユーザーのいずれかがアクセスを拒否されます。


1

ログインフェーズ中に、クライアントとサーバーが秘密のソルト値について合意できると考えてみましょう。その後、サーバーは各更新でカウント値を提供し、クライアントが(シークレットソルト+カウント)のハッシュで応答することを期待します。潜在的なハイジャッカーはこの秘密のソルト値を取得する方法がないため、次のハッシュを生成できません。


3
しかし、誰がこの塩を盗むことができないように、クライアント側にこの塩をどのように保存しますか?
Dcortez 2016年

1

私の知る限り、セッションオブジェクトはWebサーバーに格納されているため、クライアントからアクセスできません。ただし、セッションIDはCookieとして保存され、Webサーバーがユーザーのセッションを追跡できるようにします。

セッションIDを使用したセッションハイジャックを防ぐために、要求オブジェクト内のWebサーバーでアクセスできるリモートアドレスとリモートポートの2つの属性の組み合わせを使用して、ハッシュされた文字列をセッションオブジェクト内に格納できます。これらの属性は、ユーザーセッションを、ユーザーがログインしたブラウザに結び付けます。

ユーザーが別のブラウザーまたは同じシステムのシークレットモードからログインした場合、IPアドレスは同じままですが、ポートは異なります。したがって、アプリケーションにアクセスすると、ユーザーにはWebサーバーによって別のセッションIDが割り当てられます。

以下は、あるセッションから別のセッションにセッションIDをコピーして実装およびテストしたコードです。それはかなりうまくいきます。抜け穴がある場合は、どのようにシミュレーションしたかをお知らせください。

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    HttpSession session = request.getSession();
    String sessionKey = (String) session.getAttribute("sessionkey");
    String remoteAddr = request.getRemoteAddr();
    int remotePort = request.getRemotePort();
    String sha256Hex = DigestUtils.sha256Hex(remoteAddr + remotePort);
    if (sessionKey == null || sessionKey.isEmpty()) {
        session.setAttribute("sessionkey", sha256Hex);
        // save mapping to memory to track which user attempted
        Application.userSessionMap.put(sha256Hex, remoteAddr + remotePort);
    } else if (!sha256Hex.equals(sessionKey)) {
        session.invalidate();
        response.getWriter().append(Application.userSessionMap.get(sessionKey));
        response.getWriter().append(" attempted to hijack session id ").append(request.getRequestedSessionId()); 
        response.getWriter().append("of user ").append(Application.userSessionMap.get(sha256Hex));
        return;
    }
    response.getWriter().append("Valid Session\n");
}

SHA-2アルゴリズムを使用して、以下の例を使用して値をハッシュしました baeldung SHA-256 Hashingのハッシュしました

あなたのコメントを楽しみにしています。


@zaph申し訳ありませんが、担当者を獲得するための回答を追加していません。ポイントはSHA-2暗号化でもありません。しかし、私が別のユーザーのセッションID Cookieを別のユーザーのセッションに使用したこと、つまり、元の質問のようにセッションハイジャックを検出できたという事実。私は自分のソリューションをテストし、それが機能することを発見しました。しかし、私はこれの専門家ではないので、コミュニティに私の答えが十分であるかどうかを確認してもらいたいと思います。多分あなたは私のコードスニペットが何をするかを見て、それが質問に答えるかどうかを決めることができます。ありがとう!
Jzf 2018

@zaph間違いを指摘していただきありがとうございます。私はあなたの提案に従って私の答えを更新しました。回答が役に立ったと思われる場合は、反対票を削除してください。
Jzf 2018

0

リスクを減らすために、元のIPをセッションに関連付けることもできます。このように、攻撃者がセッションを使用するには、同じプライベートネットワーク内にいる必要があります。

リファラーヘッダーのチェックもオプションの1つですが、それらはより簡単に偽装されます。


7
いいえ、元のIPは変更される可能性があるため、元のIPを使用することはできません。動的IP、ユーザーが一時的に切断されたときに変更、またはプロキシファームの(暗黙的または明示的)使用によって変更されます。また、同じISPからのセッションハイジャッカーは、正当なユーザーと同じプロキシとIPを使用する可能性があります...
Olaf Kock

1
PHP-Nukeには、セッションアプローチについての良いページがあり、IPへのフックがすべてのISPで機能しない方法について詳しく説明していますphpnuke.org/…
Sembiance

4
IPの変更は、モバイルインターネットプロバイダーでは非常に一般的です。ボーダフォンを使用すると、私のリクエストはすべてのリクエストで変化します。
ブレーズ

1
少し古い投稿ですが、これをさらに進めるために。IPは前述のように悪い考えです。前述のように、モバイルユーザーはIPをローミングする傾向があります。過去の一部のISPにはローミングIP(AOLなど)もありましたが、このアプローチはIPv4 IPが不足している現在、より一般的になっています。そのようなISPには、Plus netとBTが含まれます
Peter

-15

保護する:

$ip=$_SERVER['REMOTE_ADDER'];
$_SESSEION['ip']=$ip;

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