この文書は2016年以降更新されていません

セッション管理に関するチートシート

OWASP 作成
ジャンプ先: 移動検索
Cheatsheets-header.jpg

最終改訂日 (yy/mm/dd): 2015/10/05

はじめに

Web 認証、セッション管理、およびアクセス制御

Web セッションとは、同一ユーザーに関連付けられた、ネットワーク HTTP リクエストおよびレスポンスの一連のトランザクションのことです。最近の複雑な Web アプリケーションでは、複数のリクエストの間、各ユーザーについての情報や状態を保持することが必要になります。そのため、セッションには、アクセス権やローカライズ設定などの変数を確立できる機能があります。その変数は、セッションが終わるまで、ユーザーと Web アプリケーションとのあらゆる対話に適用されます。

Web アプリケーションは、最初のユーザーリクエストの後に、匿名ユーザーを追跡記録するセッションを作成できます。ユーザーの言語設定の維持が一例です。さらに、Web アプリケーションは、一度ユーザー認証が完了してから、以後のセッションを使用します。これにより、後続のリクエストでユーザーを識別できるだけでなく、セキュリティアクセス制御、ユーザーの非公開データへの許可されたアクセスが適用可能になり、アプリケーションの使い勝手が向上します。そのため、現在の Web アプリケーションは、認証前と認証後どちらに対してもセッション管理を行うことが可能です。

認証済みセッションが確立されると、セッション ID (またはトークン) は、アプリケーションで使用される最強の認証方法 (ユーザー名とパスワード、パスフレーズ、OTP (One Time Password)、クライアント証明書、スマートカード、生体認証 (指紋や網膜) など) と同等の役割を一時的に果たします。次の OWASP の認証に関するチートシートを参照してください。https://www.owasp.org/index.php/Authentication_Cheat_Sheet

HTTP は、ステートレスなプロトコルです (RFC2616 [5])。このプロトコルでは、リクエストと応答のペアが、Web とのやり取りごとに独立しています。そのため、セッションの概念を取り入れるには、Web アプリケーションで一般的に使用される認証とアクセス制御 (または許可) の両方のモジュールをリンクさせた、セッション管理機能の実装が必要になります。

Session-Management-Diagram Cheat-Sheet.png

セッション ID やトークンは、ユーザー認証の資格情報を (ユーザーセッションの形式で)、ユーザー HTTP トラフィック、および Web アプリケーションによって適用される該当のアクセス制御にバインドします。最新の Web アプリケーションに存在する、これら 3 つのコンポーネント (認証、セッション管理、およびアクセス制御) の複雑さと、その実装とバインディングが Web 開発者によってのみ行えるという事実 (Web 開発のフレームワークで、これらのモジュール間の厳格な関連付けが提供されていないため) により、セキュアなセッション管理モジュールの実装は、非常に困難なものになっています。

セッション ID の開示、取得、予測、ブルートフォース、または固定は、セッションハイジャック (またはサイドジャック) 攻撃につながります。この攻撃では、攻撃者は Web アプリケーション内で完全に被害者ユーザーになりすますことができます。攻撃者は、標的型攻撃と汎用的な攻撃という 2 種類のセッションハイジャック攻撃を実行します。標的型攻撃の場合、攻撃者は、特定の (権限付与された) Web アプリケーションの被害者ユーザーになりすますことを目指します。汎用的な攻撃の場合、攻撃者は、Web アプリケーションの有効な、または正当なユーザーになりすます (それらのユーザーとしてのアクセス権を獲得する) ことを目指します。


セッション ID のプロパティ

Web アプリケーションで、認証された状態を維持し、ユーザーの進行を追跡するために、アプリケーションはユーザーにセッション識別子 (セッション ID やトークン) を提供します。この識別子は、セッションの作成時に割り当てられ、セッションが終わるまでユーザーと Web アプリケーションによって共有され交換されます (HTTP リクエストごとに送信されます)。セッション ID は、"名前=値" のペアです。

セキュアなセッション ID を実装するために、識別子 (ID またはトークン) の生成は、次のプロパティを満たす必要があります。

セッション ID 名のフィンガープリント

セッション ID に使用する名前は、ID の目的と意味について、極端に説明的であったり、不要な詳細を知らせるようなものであってはいけません。

ほとんどの一般的な Web アプリケーション開発フレームワークで使用されているセッション ID 名は、PHPSESSID (PHP)、JSESSIONID (J2EE)、CFID & CFTOKEN (ColdFusion)、ASP.NET_SessionId (ASP .NET) など、簡単にフィンガープリントを採取できます [0]。そのため、セッション ID 名によって、Web アプリケーションに使用されたテクノロジとプログラミング言語が開示されてしまいます。

Web 開発フレームワークの既定のセッション ID名は、「id」などの汎用的な名前に変更することを推奨します。

セッション ID の長さ

セッション ID には、ブルートフォース攻撃を防止するために十分な長さが必要です。ブルートフォース攻撃では、攻撃者は ID 値の範囲をすべて調べて、有効なセッションの存在を確認する方法をとるためです。

セッション ID の長さは、少なくとも 128 ビット (16 バイト) にする必要があります。

: 128 ビットというセッション ID の長さは、次のセクション「セッション ID のエントロピー」の前提に基づいた参考値として示しています。ただし、この数字は最低限必要な絶対的な長さとは限りません。その他の実装の要因が強度に影響するためです。たとえば、よく知られた Microsoft ASP.NET の実装では、セッション ID に 120 ビットの乱数 (20 桁の文字列 [10]) が使用されています。これは、非常に効果的なエントロピーを提供しており、その結果、推測やブルートフォース攻撃を回避するのに十分と見なされています。

セッション ID のエントロピー

セッション ID は、攻撃を防ぐために予測不可でなければなりません (十分にランダムな値でなければなりません)。攻撃者は、統計分析手法を用いて、有効なセッションの ID を推測、予測しようとするためです。このためには、優れた PRNG (擬似乱数発生ルーチン) を使用する必要があります。

セッション ID は、少なくとも 64 ビットのエントロピーを提供する必要があります (優れた PRNG を使用している場合、この値はセッション ID の半分の長さになります)。

: セッション ID のエントロピーは、実際にはその他の外部の計測困難な要因に影響を受けます。Web アプリケーションが一般的に保持する同時アクティブセッション数、絶対的なセッション有効期限切れタイムアウト、攻撃者が実行可能な、また対象の Web アプリケーションがサポート可能な 1 秒当たりのセッション ID 推測数などの多くの要因があります [2]。64 ビットのエントロピーを持つセッション ID を使用している場合、Web アプリケーションで使用可能な有効な同時セッション数が 100,000 件で、攻撃者が 1 秒当たり 10,000 件の推測を実行すると仮定すると、有効なセッション ID の推測に成功するには、少なくとも 292 年かかることになります。

セッション ID の内容 (または値)

セッション ID の内容 (または値) は、情報開示攻撃を防ぐために意味を持たないものにしなければなりません。情報開示攻撃では、攻撃者は ID の内容をデコードして、Web アプリケーションのユーザー、セッション、内部作業に関する詳細情報を抽出しようとするためです。

セッション ID は、クライアント側における単なる識別子でなければならず、その値に機密情報 (PII など) を絶対に含めてはいけません。セッション ID に関わる意味、ビジネスロジックまたはアプリケーションロジックは、セッションオブジェクトやセッション管理データベース、リポジトリなど、サーバー側に保管しなければなりません。保管された情報には、クライアントの IP アドレス、User-Agent、電子メール、ユーザー名、ユーザー ID、役割、特権レベル、アクセス権限、言語設定、アカウント ID、現在の状態、最終ログイン、セッションタイムアウト、その他の内部セッション情報が含まれます。セッションオブジェクトとプロパティに、クレジットカード番号などの機密情報が含まれている場合、セッション管理リポジトリを厳格に暗号化して保護する必要があります。

SHA1 (160 ビット) などの暗号ハッシュ機能を使用して、暗号強度の高いセッション ID を作成することを推奨します。


セッション管理の実装

セッション管理の実装では、セッション ID を共有し、継続的に交換するために、ユーザーと Web アプリケーション間で使用する交換メカニズムを定義します。セッション状態を Web アプリケーション内で維持するために HTTP で使用可能なメカニズムは複数あります。Cookie (標準 HTTP ヘッダー)、URL パラメーター (URL 書き換え - RFC 2396)、GET リクエストの URL 引数、POST リクエストの body 引数、非表示形式のフィールド (HTML 形式)、専用の HTTP ヘッダーなどです。

セッション ID 交換メカニズムは、トークンの有効期限日時やきめ細かい使用制限など、高度なトークンプロパティの定義が可能なメカニズムをお勧めします。Cookie (RFC 2109、2965、6265 [1]) が、セッション ID 交換メカニズムとして最も広く使用されているのはこのためで、他の手法では使用できない高度な機能を提供しています。

ID が URL に含まれているものなど、使用するセッション ID 交換メカニズムによっては、 (Web リンクやログ、Web ブラウザー履歴やブックマーク、Referer ヘッダーや検索エンジンなどで) セッション ID が開示されたり、ID の操作やセッション固定攻撃など、他の攻撃にさらされやすくなる場合があります。

組み込みセッション管理の実装

J2EE、ASP .NET、PHP、その他の Web 開発フレームワークは、独自のセッション管理機能と関連した実装を提供しています。ゼロから独自で作成するよりも、これらの組み込みフレームワークを使用することを推奨します。これらは、世界中のさまざまな Web 環境で使用されており、長期にわたって Web アプリケーションセキュリティと開発のコミュニティによってテストされてきた実績があるためです。

ただし、これらのフレームワークが過去にさまざまな脆弱性や弱点を露呈してきたことも忘れてはなりません。つまり、想定される既知の脆弱性をすべて修正した最新バージョンを常に使用すること、また本書に記載された推奨事項に従ってデフォルトの構成を見直し変更することで、セキュリティの強化を図ることが重要です。

セッション ID の一時保存のためにセッション管理メカニズムが使用するストレージ機能やリポジトリは、安全に保護されている必要があり、セッション ID をローカルまたはリモートでの、偶発的な開示や不正アクセスから保護しなければなりません。

使用されるセッション ID 交換メカニズムと受け入れるセッション ID 交換メカニズム

Web アプリケーションは、セッション ID 交換管理に Cookie を使用する必要があります。URL パラメーターなど、別の交換メカニズムを使用してユーザーがセッション ID を送信した場合、Web アプリケーションは、セッション固定を阻止する防御戦略の一環として、そのセッション ID の受け入れを回避する必要があります。

: Web アプリケーションが自身のデフォルトのセッション ID 交換メカニズムとして Cookie を使用していても、他の交換メカニズムも受け入れる場合があります。そのため、セッション ID の処理時および管理時に Web アプリケーションが現在受け入れているすべての異なるメカニズムを徹底的にテストすることによって確認し、受け入れるセッション ID 追跡メカニズムを Cookie のみに制限する必要があります。過去には、特定の条件を満たした場合に (Cookie をサポートしない Webクライアントの識別や、ユーザーのプライバシーの問題から Cookie を受け入れない場合など)、一部の Web アプリケーションでは、URL パラメーターを使用したり、Cookie から URL パラメーターへの切り替え (自動 URL の書き換え) を行っていました。

トランスポート層セキュリティ

セッション ID 交換をネットワークトラフィックにおいて能動的な傍受や受動的な漏えいから守るには、ユーザーの資格情報が交換される認証プロセスだけでなく、Web セッション全体に対して暗号化された HTTPS (SSL/TLS) 接続を使用することが必須です。

また、Cookie の “Secure” 属性 (下記参照) を使用して、セッション ID が暗号化されたチャネルを通じて交換されるようにする必要があります。暗号化された通信チャネルを使用することで、一部のセッション固定攻撃からセッションを保護することもできます。このような攻撃では、攻撃者は、Web トラフィックを傍受し操作して、被害者の Web ブラウザー上にセッション ID を挿入 (固定) するためです [4]。

以下の一連の HTTPS (SSL/TLS) ベストプラクティスは、セッション ID の保護 (特に Cookie を使用している場合) と、Web アプリケーション内での HTTPS との統合の容易化に重点を置いています。

  • Web アプリケーションは、該当セッションを HTTP から HTTPS に切り替えることも、その逆も絶対に行ってはいけません。セッション ID がネットワークで暗号化されていない状態で開示されてしまうためです。
  • Web アプリケーションは、同じホスト上 (または同じドメイン上。Cookie の “domain” 属性を参照) で暗号化されたコンテンツと暗号化されていないコンテンツを混在させてはいけません (HTML ページ、イメージ、CSS、Javascript ファイルなど)。暗号化されていないチャネルを介した Web オブジェクトのリクエストによってセッション ID が開示されてしまう場合があるためです。
  • 一般的に、Web アプリケーションは、公開用の暗号化されていないコンテンツと、非公開の暗号化されたコンテンツを同じホストから提供してはいけません。2 つの異なるホストを使用することを推奨します。公開用コンテンツについては、HTTP (暗号化されていない) を使用した www.example.com、非公開の機密コンテンツについては、HTTPS (暗号化されている) を使用した secure.example.com というように 2 つのホストを使用します (セッションが発生する場所)。前者のホストは、ポート TCP/80 のみを開き、後者のホストは、ポート TCP/443 のみを開きます。
  • Web アプリケーションは、極めて一般的なホームページでの HTTP から HTTPS へのリダイレクト (30x HTTP レスポンスを使用) を避けるべきです。攻撃者は、この単一の保護されていない HTTP リクエスト / レスポンス交換を利用して、有効なセッション ID の収集 (または固定) を行うことができるためです。
  • Web アプリケーションは、HTTP Strict Transport Security (HSTS) (以前の STS) を使用して、HTTPS 接続を強制適用する必要があります。

次の OWASP のトランスポート層の保護に関するチートシートを参照してください。https://www.owasp.org/index.php/Transport_Layer_Protection_Cheat_Sheet

SSL/TLS (HTTPS) は、セッション ID の推測、ブルートフォース、クライアント側での改ざん、または固定に対する防御には役に立たない点に注意してください。ただ、セッション ID をネットワークトラフィックで開示させて取得するという攻撃は、現在最も多用される攻撃です。


Cookie

Cookie に基づくセッション ID 交換メカニズムは、Cookie 属性の形式で複数のセキュリティ機能を提供します。以下の Cookie 属性を使用して、セッション ID の交換を保護できます。

Secure 属性

Cookie の “Secure” 属性は、Web ブラウザーに対して、暗号化された HTTPS (SSL/TLS) 接続のみを使用して Cookie を送信するように指示します。このセッション保護メカニズムは、MitM (中間者) 攻撃によるセッション ID の開示を防ぐうえで必須です。このメカニズムによって、攻撃者は Web ブラウザーのトラフィックから簡単にセッション ID を取得できなくなります。

Web アプリケーションに通信で HTTPS のみを使用するように強制しても (HTTP のポート TCP/80 が Web アプリケーションホストで閉じられている場合でも)、 Cookie の “Secure” 属性が設定されていなければセッション ID の開示を防ぐことはできません。Web ブラウザーをだまして、暗号化されてない HTTP 接続でセッション ID を開示させることができるためです。攻撃者は、被害者ユーザーのトラフィックを傍受し、操作して、暗号化されていない HTTP 参照を Web アプリケーションに挿入します。この HTTP 参照により、Web ブラウザーはセッション ID を暗号化されていない状態で送信してしまいます。

HttpOnly 属性

Cookie の “HttpOnly” 属性は、Web ブラウザーに対して、DOM document.cookie オブジェクトを介して Cookie にアクセスするスクリプト (JavaScript または VBscript) の機能を許可しないように指示します。このセッション ID 保護は、XSS 攻撃によるセッション ID の盗難を防ぐうえで必須です。

次の OWASP の XSS 対策チートシートを参照してください。https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet

Domain 属性および Path 属性

Cookie の “Domain” 属性は、Web ブラウザーに対して、指定されたドメイン、およびそのすべてのサブドメインにのみ Cookie を送信するように指示します。この属性が設定されていない場合、デフォルトで Cookie は発信元のサーバーにしか送信されません。Cookie の “Path” 属性は、Web ブラウザーに対して、 アプリケーション内で指定されたディレクトリまたはサブディレクトリ (またはパスやリソース) にのみ Cookie を送信するように指示します。この属性が設定されていない場合、デフォルトで Cookie は要求された、その Cookie を設定したリソースのディレクトリ (またはパス) にのみ送信されます。

これら 2 つの属性は、狭い、限られた範囲で使用することを推奨します。この意味で、“Domain” 属性は設定するべきではありません (Cookie は発信元のサーバーに送信されるように制限しておきます)。また、 “Path” 属性は、そのセッション ID を使用する Web アプリケーションパスにできるだけ限定して設定する必要があります。

“Domain” 属性を許容範囲が大きすぎる値 (“example.com” など) に設定すると、攻撃者は、同じドメインに属するさまざまなホストおよび Web アプリケーション間のセッション ID に対して攻撃を仕掛けることができます (クロスサブドメイン Cookie)。たとえば、www.example.com の脆弱性を利用して、攻撃者が secure.example.com からセッション ID にアクセスできる場合があります。

また、同じドメイン上に異なるセキュリティレベルの Web アプリケーションを混在させないことを推奨します。Web アプリケーションの 1 つに脆弱性があると、攻撃者は許容範囲の大きい “Domain” 属性 (”example.com” など) を使用して、同じドメイン上の別の Web アプリケーションに対してセッション ID を設定できてしまいます。これは、セッション固定攻撃で使用される手法です [4]。

"Path” 属性は、同じホスト上で異なるパスを使用する Web アプリケーション間で、セッション ID の分離を可能にしますが、同じホスト上で異なる Web アプリケーション (特にセキュリティレベルや範囲が異なるアプリケーション) を実行しないことを強く推奨します。これらのアプリケーションは、さまざまな他の方法を使用して、セッション ID にアクセスできてしまうためです (“document.cookie” オブジェクトなど)。また、任意の Web アプリケーションが、そのホスト上の任意のパスに Cookie を設定できてしまいます。

Cookie は、DNS スプーフィング / ハイジャック / ポイズニング攻撃に対して脆弱です。これらの攻撃では、攻撃者は、DNS 解決を操作して、該当のホストまたはドメインのセッション ID を Web ブラウザーに強制的に開示させることができます。

Expire 属性および Max-Age 属性

Cookie に基づくセッション管理メカニズムでは、非永続 (セッション) Cookie と永続 Cookie の、2 種類の Cookie を使用できます。Cookie が “Max-Age” 属性 (“Expires” 属性よりも優先される) または “Expires” 属性を提示している場合、この Cookie は永続 Cookie と考えられ、有効期限までディスク上に Web ブラウザーによって保管されます。通常、認証後にユーザーを追跡するセッション管理機能は、非永続 Cookie を使用します。これにより、現在の Web ブラウザーインスタンスが閉じられると、セッションは強制的にクライアントから消失します。そのため、セッション管理を目的とする場合、非永続 Cookie の使用を強く推奨します。セッション ID が長時間にわたって Web クライアントのキャッシュに残らず、キャッシュから攻撃者が取得することができないためです。


セッション ID のライフサイクル

セッション ID の生成と検証:Permissive なセッション管理と Strict なセッション管理

Web アプリケーションのセッション管理メカニズムには、セッション固定攻撃への脆弱性に関連して、permissive と strict の 2 種類があります。permissive なメカニズムでは、Web アプリケーションは、最初にユーザーによって有効として設定された任意のセッション ID を受け入れて、その ID で新規セッションを開始します。一方、strict なメカニズムでは、 Web アプリケーションは、その Web アプリケーションによって以前に生成されたことのあるセッション ID の値しか受け入れません。

現在最も一般的に使用されているのは、strict な (よりセキュアな) メカニズムです。開発者は、状況にかかわらず、Web アプリケーションが permissive なメカニズムを使用しないようにしなければなりません。Web アプリケーションは、生成したことのないセッション ID を決して受け入れず、受け取った場合には、新規の有効なセッション ID を生成し、ユーザーに提示するようにしなければなりません。また、このようなシナリオが発生した場合、疑わしい活動として検出され、アラートが生成されるようにします。

セッション ID を他の任意のユーザー入力として管理

セッション ID は、Web アプリケーションによって処理される他のあらゆるユーザー入力と同様に、信頼されていないものと見なす必要があります。そのため、妥当性を確認し検証する必要があります。使用しているセッション管理メカニズムに応じて、セッション ID は、GET パラメーターまたは POST パラメーター、URL や HTTP ヘッダー (Cookie など) で受け取ります。Web アプリケーションが、無効なセッション ID を検出せず除外できないまま処理してしまうと、他の Web 脆弱性の悪用をもたらす可能性があります。セッション ID がリレーショナルデータベースに保管されている場合は SQL インジェクション、セッション ID が Web アプリケーションによって保管され後で返される場合は持続型 XSS などにつながりかねません。

特権レベルに変更があるたびにセッション ID を更新

セッション ID は、関連したユーザーセッションで何らかの特権レベルの変更が発生したら、Web アプリケーションによって新たに更新、または再生成する必要があります。セッション ID の再生成が必須となる最も一般的なシナリオは認証プロセスです。ユーザーの特権レベルが非認証 (または匿名) の状態から認証済みの状態に変わるためです。Web アプリケーションにおける、パスワード変更、許可の変更、通常ユーザーの役割から管理者の役割への切り替えなど、他の一般的なシナリオも考慮しなければなりません。これらすべての Web アプリケーションの重要なページでは、前に使用されたセッション ID を無視しなければなりません。そして、重要なリソースに対して新規のリクエストを受け取るたびに、そのリクエストに新規のセッション ID を割り当てて、古い前のセッション ID を破棄しなければなりません。

最も一般的な Web 開発フレームワークでは、セッション ID を新たに更新する、セッション機能と手法が提供されています。“request.getSession(true) & HttpSession.invalidate()” (J2EE)、 “Session.Abandon() & Response.Cookies.Add(new…)“ (ASP .NET)、 “session_start() & session_regenerate_id(true)” (PHP) などです。

セッション ID の再生成は、セッション固定攻撃を阻止するうえで必須です [3]。この攻撃では、攻撃者は、他のセッションベースの攻撃の多くと異なり、被害者のセッション ID を取得するのではなく、被害者ユーザーの Web ブラウザーにセッション ID を設定します。HTTP または HTTPS のどちらを使用しているかも関係ありません。この保護によって、HTTP レスポンス分割または XSS などの、セッション固定攻撃の開始に使用できるその他の Web ベースの脆弱性の影響も軽減できます [4]。

補完的な推奨事項として、認証前と認証後に、異なるセッション ID またはトークン名 (またはセッション ID のセット) を使用する方法も挙げられます。これにより、Web アプリケーションは、両方の状態の間のユーザーセッションが開示され、バインドされるリスクを負うことなく、匿名ユーザーと認証済みユーザーを追跡することができます。

複数の Cookie を使用する際の考慮事項

Web アプリケーションが、セッション ID 交換メカニズムとして Cookie を使用し、複数の Cookie が 1 つの該当セッションに設定されている場合、Web アプリケーションは、ユーザーセッションへのアクセスを許可する前に、すべての Cookie を検証 (および Cookie 間の関係を適用) する必要があります。

一般的には、非認証 (または匿名) ユーザーを追跡するために、Web アプリケーションは、 HTTP を介して、ユーザーに認証前の Cookie を設定します。Web アプリケーションでユーザーが認証されると、新規の認証後のセキュアな Cookie が HTTPS を介して設定され、両方の Cookie 間のバインドとユーザーセッションが確立されます。Web アプリケーションが認証済みセッションについて、両方の Cookie の検証を行わない場合、攻撃者は認証前の保護されていない Cookie を使用して、認証済みのユーザーセッションにアクセスできてしまいます [4]。

Web アプリケーションが、同じ Web アプリケーション内で、異なるパスまたはドメイン範囲に対して、同じ Cookie 名を使用するのは避けてください。ソリューションが複雑になるうえに、スコーピングの問題が発生する可能性が高まるためです。


セッションの有効期限切れ

攻撃者が活動状態にあるセッションに対する攻撃を開始し、ハイジャックを実行するまでの時間を最小化するために、すべてのセッションに有効期限切れタイムアウトを設定し、セッションを活動状態のままにする時間を明確に設定しておく必要があります。Web アプリケーションによるセッションの有効期限切れの設定が不十分だと、他のセッションベースの攻撃に対するリスクが高まります。攻撃者が有効なセッション ID を再使用し、関連セッションをハイジャックするには、セッションが活動状態のままでなければならないためです。

セッションの時間間隔が短ければ短いほど、攻撃者が有効なセッション ID を使用する時間が短くなります。セッションの期限切れタイムアウトの値は、Web アプリケーションの目的と性質に応じて設定し、セキュリティと使い勝手のバランスをとる必要があります。そうして初めて、ユーザーはセッションが頻繁に期限切れになることなく、Web アプリケーションにおける操作を快適に行うことができるのです。アイドル状態のタイムアウトと絶対的なタイムアウトの値は、対象の Web アプリケーションとそのデータの重要度に大きく依存します。一般的に、アイドル状態のタイムアウトの値は、重要度の高いアプリケーションの場合、2 分から 5 分、低リスクのアプリケーションの場合、15 分から 30 分です。

セッションの有効期限が切れると、Web アプリケーションは、能動的にアクションを実行して、クライアントとサーバー両側のセッションを無効化しなければなりません。特に後者のサーバー側セッションの無効化は、セキュリティの観点から最も重要かつ必須です。

セッション交換メカニズムの多くでは、クライアント側のセッション ID 無効化アクションは、トークン値の消去が中心です。たとえば、Cookie を無効化するには、次のようにセッション ID に空の値 (無効な値) を提供し、“Expires” 属性 (または “Max-Age” 属性) を過去の日付に設定します (永続 Cookie を使用している場合)。

Set-Cookie: id=; Expires=Friday, 17-May-03 18:45:00 GMT 

サーバー側のセッションを終了して、無効化するには、セッションが期限切れになったとき、またはユーザーが能動的にログアウトしたときに 、Web アプリケーションがセッション管理メカニズムによって提供されている関数やメソッドを使用して、能動的にアクションをとる必要があります ( “HttpSession.invalidate()” (J2EE)、“Session.Abandon()“ (ASP .NET)、 “session_destroy()/unset()“ (PHP) など)。

自動的なセッションの有効期限切れ

アイドル状態のタイムアウト

すべてのセッションは、アイドル状態、または非活動状態のタイムアウトを実装する必要があります。このタイムアウトでは、まったく活動がないセッションを活動状態のままにしておく時間を定義します。該当のセッション ID について Web アプリケーションが最後に HTTP リクエストを受信したときから、ここで定義されたアイドル状態のタイムアウト期間が経過すると、セッションは終了し、無効化されます。

アイドル状態のタイムアウトにより、攻撃者が有効なセッション ID を推測し、別のユーザーでそのセッション ID を使用する機会が制限されます。しかし、該当のセッションを攻撃者がハイジャックできる場合、アイドル状態のタイムアウトでは、攻撃者のアクションを制限できません。攻撃者は定期的にセッションに活動状態を作り出して、長時間セッションを活動状態のままにすることができるためです。

セッションタイムアウト管理と有効期限は、サーバー側で適用されます。クライアントを使用してセッションタイムアウトを適用する場合、たとえばセッショントークンやその他のクライアントパラメーターを使用して時間参照 (ログインからの経過分数など) を追跡する場合、攻撃者はこれらの値を操作して、セッションの時間を長くすることができます。

絶対的なタイムアウト

すべてのセッションは、セッションの活動状態に関係なく、絶対的なタイムアウトを実装する必要があります。このタイムアウトでは、セッションを活動状態にできる最大時間を定義します。該当セッションが Web アプリケーションによって最初に作成されてから、ここで定義された絶対時間を経過すると、セッションは終了し、無効化されます。セッションが無効化されると、ユーザーは、Web アプリケーションで再度認証を行い、新しいセッションを確立しなければなりません。

絶対的なセッションタイムアウトは、攻撃者がハイジャックしたセッションを使用し、被害者ユーザーになりすますことができる時間を制限します。

更新のタイムアウト

さらに、Web アプリケーションは、更新のタイムアウトを実装することもできます。このタイムアウトを経過すると、セッション ID は自動的に新しく更新されます。ユーザーセッションの最中であっても、セッションの活動状態、アイドル状態のタイムアウトにも関係なく更新されます。

セッションが最初に作成されてから特定の時間が経過すると、Web アプリケーションはユーザーセッションについて新しい ID を再度生成し、クライアントで設定、または更新を試みます。前のセッション ID の値は、安全のために、クライアントが新規 ID を認識し、使用を開始するまでしばらくの間有効です。クライアントが現行セッション内で新規 ID に切り替えると、アプリケーションは前の ID を無効化します。

このシナリオによって、被害者ユーザーのセッションが活動状態にあっても、攻撃者がセッション ID を取得し、該当のセッション ID を再使用して、ユーザーセッションをハイジャックできる可能性のある時間を最小化します。関連したセッション ID 値は、更新のタイムアウトが期限切れになるたびに、セッション中でも定期的に自動的に新しく更新されますが、ユーザーセッションは、合法的なクライアント上で活動状態で開いたままになります。そのため、更新のタイムアウトは、アイドル状態のタイムアウトと絶対的なタイムアウトを補完する役割を果たします。特に、絶対的なタイムアウトの値が長時間の場合に有効です (ユーザーセッションを長時間開いたままにすることがアプリケーションの要件である場合)。

実装環境によっては、有効な以前のセッション ID を持つ攻撃者が、被害者のユーザーになりすましてリクエストを送信し、更新のタイムアウトの有効期限が切れた直後に、新しく更新されたセッション ID の値を最初に取得するというまれなケースも考えられます。このシナリオでは、関連のセッション ID が有効でなくなり、自分のセッションが突然終了してしまうので、被害者ユーザーは少なくとも攻撃に気がつくはずです。


手動によるセッションの有効期限切れ

Web アプリケーションは、セキュリティを意識しているユーザーが、Web アプリケーションの使用終了時に能動的にセッションを終了できるメカニズムを提供する必要があります。

ログアウトボタン

Web アプリケーションは、目に見えてアクセスが容易なログアウト (ログオフ、終了、セッションのクローズなど) ボタンを提供する必要があります。このボタンは、Web アプリケーションのヘッダーやメニューに配置し、すべての Web アプリケーションリソースとページからアクセスでき、ユーザーがいつでもセッションを手動で閉じることができるようにしなければなりません。上記のとおり、Web アプリケーションには、少なくともサーバー側でセッションを無効化できる機能は必須です。

: 残念ながら、すべての Web アプリケーションで、ユーザーが自分の現行セッションを終了できる機能を保有しているわけではありません。この場合は、PopUp LogOut Firefox アドオン [9] など、クライアント側の機能強化を使用することで、セキュリティに対して真剣なユーザーなら自分のセッションをこまめに終了し、セッションを保護することができます。

Web コンテンツのキャッシュ

セッションの終了後も、Web ブラウザーのキャッシュを使用して、セッションで交換された非公開データや機密データにアクセス可能な場合があります。そのため、Web アプリケーションは、HTTP および HTTPS を介して交換されたすべての Web トラフィックのキャッシュ処理に関して、限定的なディレクティブを使用する必要があります。つまり、“Cache-Control: no-cache,no-store” および “Pragma: no-cache” HTTP ヘッダー [5]、または同等機能を持つ META タグ、あるいはその両方をすべての Web ページ 、少なくとも機密情報を扱うページ に設定する必要があります。

Web アプリケーションで定義されたキャッシュポリシーにかかわらず、Web アプリケーションコンテンツのキャッシュ処理が許可されている場合、セッション ID をキャッシュに入れてはいけません。そのため、"Cache-Control: no-cache="Set-Cookie, Set-Cookie2"” ディレクティブを使用して、Web クライアントがセッション ID 以外をキャッシュに入れるように設定することを強く推奨します。


セッション管理に関する追加のクライアント側の防御

Web アプリケーションは、クライアント側で追加の対策を講じることで、ここまで述べたセッション管理に関する防御策を補完することができます。クライアント側の保護は、通常 JavaScript の確認と検証の形式で行われるため、万全とはいえず、スキルを備えた攻撃者なら容易に打ち破ることができます。しかし、防御の層を追加することで、侵入者が迂回しなければならない障壁を増やすことができます。

最初のログインタイムアウト

Web アプリケーションは、ログインページで JavaScript コードを使用して、ページが読み込まれ、セッション ID が付与されてからの時間を計算、計測することができます。指定された時間以後もログインが試行される場合、クライアントコードにより、ログインが許可される最大時間が経過したこと、ログインページが再度読み込まれること、そのため新規のセッション ID が取得されることをユーザーに通知するようにできます。

この追加の保護メカニズムにより、認証前セッション ID が強制的に新しく更新されるため、セッション固定攻撃に見られるような、前に使用された (または手動で設定された) セッション ID を、同じコンピューターを使用する次の被害者が再使用するというシナリオを回避できます。

Web ブラウザーウィンドウを閉じる際の強制的なセッションログアウト

Web アプリケーションは、JavaScript コードを使用して、すべての Web ブラウザータブやウィンドウを閉じる操作 (戻る操作も同様) を検知し、適切なアクションをとって、あたかもユーザーが手動でログアウトボタンを使用してセッションを終了したかのように、Web ブラウザーの終了前に現行セッションを終了させることができます。

Web ブラウザーのクロスタブセッションの無効化

Web アプリケーションは、JavaScript コードを使用して、ユーザーがログインし、セッションが確立したら、同じ Web アプリケーションに対して新規の Web ブラウザータブやウィンドウが開かれた場合にユーザーの再認証を強制的に行うようにすることができます。Web アプリケーションでは、複数の Web ブラウザータブやウィンドウが同じセッションを共有できるようにすることは好ましくありません。そのため、 Web アプリケーションでは、Web ブラウザーが複数のタブやウィンドウ間で同時に同じセッション ID を共有しないように設定することができます。

: このメカニズムは、Cookie を介してセッション ID を交換している場合には実装できません。Cookie は、すべての Web ブラウザータブ / ウィンドウで共有されるためです。

自動クライアントログアウト

Web アプリケーションは、すべての (または重要な) ページで JavaScript コードを使用して、アイドル状態のタイムアウトが期限切れになるとクライアントセッションから自動的にログアウトするようにできます。たとえば、ユーザーをログアウトページにリダイレクトするなどの手法があります (前述のログアウトボタンが使用するリソースと同じです)。

クライアント側のコードにより、サーバー側のアイドル状態のタイムアウト機能を強化することの利点として、セッションが非活動状態によって終了したことをユーザーが確認できることや、カウントダウンタイマーや警告メッセージによって、セッションがしばらくすると期限切れになることを前もってユーザーに通知できることが挙げられます。このユーザーフレンドリーなアプローチにより、サーバー側で自動的にセッションが期限切れになることで、Web ページで作業損失が発生し多大な入力データが必要になる事態を避けることができます。


セッション攻撃の検出

セッション ID 推測およびブルートフォースの検出

攻撃者が有効なセッション ID を取得するために、推測やブルートフォースを試みる場合、単一の (または一連の) IP アドレスから異なる複数のセッション ID を使用して、標的の Web アプリケーションに対して複数の順次リクエストを発信する必要があります。また、攻撃者がセッション ID の予測可能性を分析しようとする場合 (統計分析の使用など)、単一の (または一連の) IP アドレスから、標的の Web アプリケーションに対して複数の順次リクエストを発信して、新規の有効なセッション ID を取得する必要があります。

両方のシナリオともに、Web アプリケーションは、複数の異なるセッション ID を取得 (または使用) しようとする試みの回数に基づいて事態を検出し、ユーザーに警告できなければなりません。また、攻撃元の IP アドレスを遮断する機能も必要です。

セッション ID の異常の検出

Web アプリケーションは、セッション ID に関連した異常 (セッション ID の操作など) の検出に重点を置く必要があります。OWASP AppSensor Project [7] は、Web アプリケーション内に組み込み侵入検知機能を実装するためのフレームワークと方法論を提供しています。これらの機能は、検出ポイントとレスポンスアクションの形で、異常および予期しない動作の検出に重点を置いています。外部の保護層を使用しないので、ビジネスロジックの詳細や高度なインテリジェンスは、Web アプリケーション内部からしか使用できません。ここでは、複数のセッションに関連した検出ポイントを確立できます。既存 Cookie が変更、削除されたとき、新規 Cookie が追加されたとき、別のユーザーのセッション ID が再使用されたとき、ユーザーの場所や User-Agent がセッション中に変更になったときなどです。

セッション ID を他のユーザープロパティにバインド

ユーザーの不正行為やセッションのハイジャックを検出 (シナリオによっては阻止) するという目的のために、セッション ID を他のユーザーまたはクライアントのプロパティ (クライアント IP アドレス、User-Agent、クライアントベースのデジタル証明書など) にバインドすることを強く推奨します。セッションの最中に、これらのさまざまなプロパティで何らかの変更や異常を Web アプリケーションが検出した場合は、セッション操作やハイジャックの試みを示す明確な兆候であり、この単純な事実を使用して警告を発行したり、疑わしいセッションを強制終了することができます。

これらのプロパティは、Web アプリケーションがセッション攻撃への万全の防御策として使用するまでには至りませんが、Web アプリケーション検出 (防御) 機能を大きく向上させます。ただし、高度なスキルを持つ攻撃者は、同じネットワークの共有 (Wi-Fi ホットスポットなど NAT 環境では一般的) や、同じアウトバウンド Web プロキシの使用 (企業の環境では一般的) 、あるいはユーザーエージェントを手動で変更して被害者ユーザーとまったく同じに見せかけたりすることで、被害者のユーザーに割り当てられた同じ IP アドレスを再使用して、制御を迂回することができます。

セッションライフサイクルのロギング:セッション ID の作成、使用、破棄の監視

Web アプリケーションは、セッションのライフサイクル全体に関する情報を含めることによって、ロギング機能を強化する必要があります。特に、セッション ID の作成、更新、破棄などのセッション関連イベント、ログイン、ログアウト操作におけるセッション ID の使用に関する情報、セッションにおける特権レベルの変更、タイムアウトの期限切れ、無効なセッション活動 (検出時)、セッション中の重要なビジネスオペレーションを記録することを推奨します。

ログの詳細には、タイムスタンプ、ソース IP アドレス、要求された (およびセッション操作に含まれた) Web ターゲットリソース、HTTP ヘッダー (User-Agent および Referer)、GET パラメーターおよび POST パラメーター、エラーコード、メッセージ、ユーザー名 (またはユーザー ID)、そしてセッション ID (Cookie、URL、GET、POST など) などが含まれています。セッション ID などの機密データは、セッション ID のローカルまたはリモートでの漏えいや不正アクセスからセッションログを保護するうえで、ログに含めるべきではありません。しかし、一部のセッション固有情報は、ログエントリと特定のセッションを関連付けるために、ログに記録しておく必要があります。セッション ID を開示せずに、セッション固有のログ相関付けを可能にするために、セッション ID そのものではなく、セッション ID の salted ハッシュをログに記録することを推奨します。

特に、Web アプリケーションは、現在活動状態のすべてのセッションの管理に使用される、管理インターフェイス全体を保護しなければなりません。多くの場合、これらのインターフェイスは、セッション関連の問題や一般的な問題を解決するために、サポート担当者が使用します。サポート担当者は、ユーザーになり変わり、ユーザーと同じように Web アプリケーションを確認します。

セッションログは、Web アプリケーションの主要な侵入検知データソースの 1 つです。このデータを使用して、侵入防御システムが、1 つまたは複数の攻撃の検出時に、自動的にセッションを強制終了したり、ユーザーアカウントを無効化したりすることもできます。能動的な防御が実装されている場合、それらの防御アクションもログに記録する必要があります。

同時セッションログオン

同一ユーザーによる、同一または異なるクライアント IP アドレスからの、複数の同時ログオンを許可するかどうかは、Web アプリケーション設計の決定事項です。Web アプリケーションで、同時セッションログオンを許可しない場合、暗黙的に前の使用可能セッションを強制終了したり、セッションを活動状態のままにする必要があるかどうかを、旧セッション、新規セッション、または両方のセッションでユーザーに確認したりするなど、新規の各認証イベント後に効果的なアクションをとる必要があります。

Web アプリケーションに、いつでも活動状態のセッションの詳細を確認し、同時ログオンに関して監視してユーザーに警告できるユーザー機能を追加することを推奨します。また、リモートで手動によるセッションの強制終了ができ、IP アドレス、User-Agent、ログイン日時、アイドル状態の時間など、複数のクライアント詳細情報を記録することで、アカウント活動履歴 (ログブック) を追跡できるユーザー機能を提供することを推奨します。


セッション管理の WAF 防御

Web アプリケーションソースコードが入手できない場合、または変更できない場合、上記に記載した複数のセキュリティ推奨事項およびベストプラクティスの実装に必要な変更には、Web アプリケーションアーキテクチャの全面的な設計見直しが必要になるため、短期間に容易に実装できない場合があります。このような場合、あるいは Web アプリケーションの防御を補完したい場合、またできるだけ Web アプリケーションのセキュリティを維持するという目的の場合、 Web アプリケーションファイアウォール (WAF) など、外部の防御策を使用することを推奨します。この方法によって、これまで述べたセッション管理の脅威を軽減することができます。

Web アプリケーションファイアウォールは、セッションベースの攻撃に対して検出と防御機能を提供します。WAF を使用すれば、"Secure” フラグおよび “HttpOnly” フラグなど、Cookie のセキュリティ属性を強制的に適用し、新規 Cookie を設定する、すべての Web アプリケーションレスポンスの “Set-Cookie” ヘッダーに基本的な書き換えルールを適用するのは容易です。一方、より高度な機能を実装して、WAF でセッションや対応するセッション ID を追跡することもできます。また、セッション固定に対するあらゆる種類の防御の適用 (特権変更が検出された際のクライアント側でのセッション ID の更新による)、スティッキーセッションの適用 (セッション ID と IP アドレスや User-Agent など、その他のクライアントプロパティ間の関係の検証による)、セッションの期限切れの管理 (クライアントと Web アプリケーションの両方にセッションを強制的に終了させることによる) などを可能にできます。

オープンソース ModSecurity WAF は、OWASP Core Rule Set [6] に加えて、検出、セキュリティ Cookie 属性の適用、セッション固定攻撃への対抗手段、スティッキーセッションの強制適用のためのセッション追跡機能を提供します。


関連資料

[0] "OWASP Cookies Database" OWASPhttps://www.owasp.org/index.php/Category:OWASP_Cookies_Database

[1] "HTTP State Management Mechanism" RFC 6265IETFhttp://tools.ietf.org/html/rfc6265

[2] "Insufficient Session-ID Length" OWASPhttps://www.owasp.org/index.php/Insufficient_Session-ID_Length

[3] Session Fixation。 Mitja Kolšek2002http://www.acrossecurity.com/papers/session_fixation.pdf

[4] "SAP: Session (Fixation) Attacks and Protections (in Web Applications)"Raul SilesBlackHat EU 2011

https://media.blackhat.com/bh-eu-11/Raul_Siles/BlackHat_EU_2011_Siles_SAP_Session-Slides.pdf

https://media.blackhat.com/bh-eu-11/Raul_Siles/BlackHat_EU_2011_Siles_SAP_Session-WP.pdf

[5] "Hypertext Transfer Protocol -- HTTP/1.1" RFC2616IETFhttp://tools.ietf.org/html/rfc2616

[6] "OWASP ModSecurity Core Rule Set (CSR) Project" OWASPhttps://www.owasp.org/index.php/Category:OWASP_ModSecurity_Core_Rule_Set_Project

[7] "OWASP AppSensor Project" OWASPhttps://www.owasp.org/index.php/Category:OWASP_AppSensor_Project

[8] "HttpOnly Session ID in URL and Page Body | Cross Site Scripting" http://seckb.yehg.net/2012/06/httponly-session-id-in-url-and-page.html

[9] PopUp LogOut Firefox add-on https://addons.mozilla.org/en-US/firefox/addon/popup-logout/ & http://popuplogout.iniqua.com

[10] "How and why session IDs are reused in ASP.NET" https://support.microsoft.com/en-us/kb/899918

Authors and Primary Editors

Raul Siles (DinoSec) - raul[at]dinosec.com

Other Cheatsheets

Developer Cheat Sheets (Builder)

Assessment Cheat Sheets (Breaker)

Mobile Cheat Sheets

OpSec Cheat Sheets (Defender)

Draft Cheat Sheets