HTTP セッション使用のベスト・プラクティス
このトピックでは、HTTP セッションの実装のベスト・プラクティスについて説明します。

- HTTP セッションを保護するためにセキュリティー統合を使用可能にする
HTTP セッションは、セッション ID によって識別されます。 セッション ID は、実行時に生成される疑似乱数です。 セッション・アタックは HTTP セッションに対する既知のアタックで、ネットワークを経由するすべての要求 がセキュア接続 (すなわち HTTPS) を介するように強制することによって防ぐことができます。 しかし、そうすると SSL 接続のパフォーマンスが低下するため、カスタマー環境のすべての構成でこの制約が実行されているとは限りません。 このような緩やかな方式であるため、HTTP セッションはアタックを受けやすく、 このぜい弱性のために WebSphere® Application Server では、HTTP セッション と WebSphere Application Server セキュリティーを緊密に統合するオプションが用意されています。 WebSphere Application Server でセキュリティーを使用可能にすると、 セッションへのアクセスが、そのセッションを作成したユーザーだけに許可されるという方法で保護されます。
- 終了時には javax.servlet.http.HttpSession.invalidate() を使用して、
HttpSession オブジェクトを解放する。HttpSession オブジェクトは、以下のことが起こるまで、Web コンテナー内で存続します。
- アプリケーションが明示的かつプログラマチックに javax.servlet.http.HttpSession.invalidate メソッドを使用してそのオブジェクトを解放する。 たいていの場合、プログラマチックな無効化機能は、アプリケーション・ログアウト機能の一部です。
- 割り振られた HttpSession の有効期限が切れたときに、WebSphere Application Server が その HttpSession を破棄する (デフォルトの有効期限は 1800 秒、つまり 30 分)。 WebSphere Application Server は、セッション管理の設定に基づき、メモリー内に一定数の HTTP セッションしか維持できません。 分散セッションの場合は、 メモリーの最大キャッシュ制限に達すると、 セッション管理機能はキャッシュから最低使用頻度 (LRU) のセッションを除去し、セッションのために場所をあけます。
- HttpSession オブジェクトを各サーブレットまたは JSP ファイルの外に保存したり、
再利用したりすることは回避する。
HttpSession オブジェクトは、 HttpRequest の機能であり (req.getSession メソッドによってのみ取得可能)、 そのコピーはサーブレットまたは JSP ファイルの service メソッドの存続期間中のみ有効です。 HttpSession オブジェクトをキャッシュに入れて、 それをサーブレットまたは JSP ファイルの有効範囲外で参照することはできません。
- HTTP セッションに保管する新規オブジェクトを開発する場合は、java.io.Serializable インターフェースを
実装する。
クラスのシリアライズ可能性は、java.io.Serializable インターフェースを実装するクラスによって使用可能になります。 java.io.Serializable インターフェースを実装することにより、分散セッションの使用時に、オブジェクトはシリアライズされるようになります。 このインターフェースを実装しないクラスは、状態がシリアライズまたはデシリアライズされません。 このため、クラスがシリアライズ可能なインターフェースを実装しない場合、JVM はその状態をデータベースまたは別の JVM に保持できません。 シリアライズ可能なクラスのすべてのサブタイプはシリアライズ可能です。 次に例を挙げます。
public class MyObject implements java.io.Serializable {...}
transient とマークされていないインスタンス変数オブジェクトがすべてシリアライズ可能であることを確認してください。 シリアライズ可能でないオブジェクトをキャッシュすることはできません。
Java™ Servlet 仕様に準拠させるため、コンテナーがオブジェクトを格納するセッションのマイグレーションで必要なメカニズムをサポートできない場合は、分散サーブレット・コンテナーがオブジェクトの IllegalArgumentException を作成する必要があります。 例外が作成されるのは、分散可能を選択した場合だけです。
- データベースまたは WebSphere eXtreme Scale いずれかを使用したフェイルオーバー中にデータ損失が発生しないように、セッション状態のフェイルオーバーを有効にする場合には <codeph>write frequency=END_OF_SERVICE</codeph> を使用します。 各要求の終了時にセッション・データがデータベースまたはデータ・グリッドに格納されるため、データ損失は発生しません。 この動作により、要求時間が長くなるためパフォーマンスが低下します。
- セッションに追加する Java オブジェクトが正しいクラス・パスにあることを確認する。
Java オブジェクトをセッションに追加する場合、それらのオブジェクトのクラス・ファイルを正しいクラスパスに置くか (エンタープライズ・アプリケーションで複数の Web モジュール間での共有を利用する場合はアプリケーション・クラスパス、Servlet 2.2 準拠セッションの共有を使用する場合は Web モジュール・クラスパスに置く)、あるいは、WebSphere Application Server で使用される他のサーブレットを含むディレクトリーに配置します。セッションがクラスター化している場合、 このアクションはクラスター内のすべてのノードに適用されます。
HttpSession オブジェクトはユーザーがアクセスする可能性のあるサーブレット間で共有されるので、 競合を避けるために、サイト全体での統一された命名規則を設定することを検討してください。
- 大容量のオブジェクト・グラフを HttpSession オブジェクト内に保管することを回避する。
ほとんどのアプリケーションでは、 各サーブレットが必要とするセッション・データは、全体のうちの一部のみです。 ただし、そのデータを単一のラージ・オブジェクトとして HttpSession オブジェクト内に保管すると、 アプリケーションは毎回 WebSphere Application Server にセッション・データ全体を強制的に処理させます。
- セッション・アフィニティーを使用して、WebSphere Application Server でより高い確立でキャッシュにヒットできるようにする。
WebSphere Application Server には、HTTP Server プラグイン内でセッション・アフィニティーを支援する機能があります。 プラグインは、Cookie データ (またはエンコードされた URL) をブラウザーから読み取り、 割り当てられたセッション・キーに基づいて、該当するアプリケーションま たはクローンに要求を送信できるようにします。 この機能は、メモリー内のキャッシュの使用量を増やし、 データベースまたは別の WebSphere Application Server インスタンスへのヒット数を削減します。
- セッション・アフィニティーを最大限に使用し、アフィニティーの中断を回避する。
セッション・アフィニティーを適切に使用すると、WebSphere Application Server のパフォーマンスを高めることができます。 WebSphere Application Server 環境のセッション・アフィニティーにより、 セッション・オブジェクトのメモリー内キャッシュを最大化し、 データベースまたは別の WebSphere Application Server インスタンスへの読み込み回数を削減できます。 セッション・アフィニティーは、 ユーザーが対話しているアプリケーションのサーバー・インスタンス内のセッション・オブジェクトをキャッシュに入れることによって機能します。 アプリケーションが、あるサーバー・グループの複数のサーバーにデプロイされている場合、 アプリケーションはそれらのどのサーバーにもユーザーを誘導できます。 ユーザーがサーバー 1 から開始し、少し後でサーバー 2 に到達する場合、 サーバー 2 が稼働しているサーバー・インスタンスがデータベースを読み取れるように、 サーバーは、すべてのセッション情報を外部ロケーションに書き込む必要があります。 セッション・アフィニティーを使用すると、このデータベース読み込みを回避できます。 セッション・アフィニティーを用いて、ユーザーは最初の要求に対してサーバー 1 から開始し、 その後は、後続のすべての要求ごとに、サーバー 1 に戻されます。 サーバー 1 は、セッション情報を取得するためにキャッシュだけを調べればよく、 情報を取得するためにセッション・データベースを呼び出す必要がなくなります。
セッション・アフィニティーを中断することなく、パフォーマンスを向上させることができます。 セッション・アフィニティーの中断を回避するためのいくつかの提案を以下に示します。- 可能であれば、すべての Web アプリケーションを 1 つのアプリケーション・サーバー・インスタンスに結合し、モデル化またはクローン化を使用してフェイルオーバーのサポートを提供する。
- マルチ・フレーム JSP ファイルを使用する場合は、 フレーム・ページ用のセッションを作成し、フレーム内のページ用にはセッションを作成しない。 (このトピックで後述する説明を参照。)
- マルチ・フレーム・ページを使用する場合は、以下のガイドラインに従う。
- セッションの作成は、単一のフレーム内でのみ行うか、 任意のフレーム・セットにアクセスする前に行う。 例えば、ブラウザーに関連付けられているセッションが存在せず、 かつユーザーがマルチフレーム JSP ファイルにアクセスした場合は、 ブラウザーは JSP ファイルに対して並行要求を発行します。 それらの要求はどのセッションにも含まれないため、 結果的に JSP ファイルは複数のセッションを作成し、 すべての Cookies がブラウザーに戻されます。 ブラウザーは、最後に着信した Cookie のみを受け入れます。 したがって、最後の Cookie と関連付けられたセッションを検索できるのは、クライアントだけです。 JSP ファイルを使用するマルチフレームのページにアクセスする前に、 セッションを作成することをお勧めします。
- デフォルトでは、JSP ファイルは request.getSession(true) メソッドを使用して、HTTPSession を取得します。 このため、デフォルトでは、JSP ファイルは、クライアントのセッションがない場合に新規セッションを作成します。ブラウザー内の各 JSP ページが新規セッションを要求しても、 ブラウザー・インスタンスごとに使用されるセッションは 1 つだけです。 開発者は、<% @ page session="false" %> を使用して、セッションにアクセスしない JSP ファイルから 自動的にセッションを作成する機能を、オフにできます。 ページがセッション情報にアクセスする必要がある場合、 開発者は、<%HttpSession session = javax.servlet.http.HttpServletRequest.getSession(false); %> を使用して、JSP ファイルを作成する 元のセッションによって作成された、 既存のセッションを取得できます。 このアクションにより、フレーム・ページの初期ロードの際にセッション・アフィニティーを中断しないで済むようになります。
- 唯一のフレームを使用してセッション・データを更新する。 フレーム・セットを使用している場合、要求は並行して HTTP サーバーに送信されます。 セッション・データの変更は、セッション変更が並行フレーム・セット内のセッション変更によって上書きされないよう、1 つのフレーム内だけで行なうことをお勧めします。
- フレームがさまざまな Web アプリケーションをポイントするマルチフレーム JSP ファイルの使用を回避する。このアクションにより、別の Web アプリケーションによって作成されたセッションが失われることになります。これは、第 1 の Web アプリケーションの JSESSIONID Cookie が、第 2 の Web アプリケーションによって作成された JSESSIONID によって上書きされるためです。
- セキュリティー統合を有効にしたセッションを使用するサーブレットまたは JSP ファイルにセキュリティーを適用する場合は、
すべてのページ (一部だけでなく) を保護する。
セキュリティーとセッションに関しては、すべてを保護するか、まったく保護しないかのいずれかです。 一部の時間だけセッション状態へのアクセスを保護するのは無意味です。 セッション管理機構でセキュリティー統合が使用可能になっている場合、 セッションの作成元またはアクセス元となるすべてのリソースは、保護か非保護かのいずれかでなければなりません。 保護されているリソースと保護されていないリソースを混在させることはできません。
数ページしか保護しない場合の問題点は、 保護ページで作成されたセッションが許可ユーザーの ID の下に作成されるということです。 他の保護ページ内のこれらのセッションにアクセスできるのは、同じユーザーだけです。 非許可ユーザーによるこれらのセッションの使用を防ぐため、 非保護ページからこれらのセッションにアクセスすることはできません。 非保護ページから要求が出されると、 アクセスは拒否され、UnauthorizedSessionRequestException エラーが作成されます。 (UnauthorizedSessionRequestException はランタイム例外であり、ログに記録されます。)
- セッション・データを読み取り、更新を頻繁に行うアプリケーションでは、
手動更新を行い、sync() メソッドを使用するか、時間ベースの書き込みを行う。
アプリケーションがセッションを使用している場合、 そのセッションに対するデータの読み取りや書き込みが行われるたびに、書き込み頻度として END_OF_SERVICE を使用して、 LastAccess 時間フィールドは更新されます。 データベース・セッションが使用される場合、 そのデータベースへの新規書き込みが行われます。 このアクティビティーは、パフォーマンスに対するヒットであり、「 手動更新」オプションを使用したり、レコードの読み取りや書き取りのたびにではなく、 データ値が更新された場合に限りレコードをデータベースに書き戻したりすることによって回避できます。
手動更新を使用するには、セッション管理サービスでそれをオンにします。 (ロケーション情報については、前述の表を参照してください。) さらに、アプリケーション・コードは、 汎用 HttpSession ではなく com.ibm.websphere.servlet.session.IBMSession クラスを使用する必要があります。 IBMSession オブジェクトには sync メソッドがあります。このメソッドは、 セッション・オブジェクト内のデータをデータベースに書き込むよう WebSphere Application Server に伝えます。 このアクティビティーにより、開発者は、必要な場合に限りセッション情報を持続させることによって、 パフォーマンスを全体的に向上させることができます。
注: 手動更新の使用に代わる別の方法は、 定期更新を使用して、異なる時間間隔でデータを持続させることです。 このアクションにより、手動更新スキームと類似した結果が得られます。 - 高いパフォーマンスを得るため、以下の提案を実装する。
- アプリケーションがセッション・データを頻繁に変更しない場合は、「 手動更新」と sync 関数 (または定期間隔更新) を使用して、効率的にセッション情報を持続させる。
- セッション内に保管されるデータの量をできるだけ少なくする。 データを保持するセッションを安易に使用すると、 セッション・オブジェクト内に保管されるデータが多くなりすぎることがあります。 セッションを効果的に使用するために、 データ・ストレージとパフォーマンスの適正なバランスを判断してください。
- データベース・セッションを使用する場合は、セッション・データベース専用のデータベースを使用する。 アプリケーション・データベースは使用しないでください。これにより、JDBC 接続に対する競合を回避し、 データベース・パフォーマンスを向上させることができます。
- メモリー間セッションを使用する場合は、クラスターのサイズが大きくなり、 スケーリングが縮小するのに応じて、区分化 (グループまたは単一レプリカのいずれか) を使用する。
- WebSphere Application Server 用の最新のフィックスパックを入手していることを確認する。
- 以下のツールを使用して、セッション・パフォーマンスのモニターに役立てる。
- com.ibm.servlet.personalization.sessiontracking.IBMTrackerDebug サーブレットを実行する。 このサーブレットを実行するには、サーブレットの実行元の Web アプリケーションでサーブレットを起動する回路が稼働していなければなりません。あるいは、実行元のアプリケーションでこのサーブレットを明示的に構成することもできます。
- WebSphere Application Server に同梱されている WebSphere Application Server Resource Analyzer を使用して、WebSphere Application Server 環境のアクティブ・セッションおよび統計をモニターする。
- DB2® で「Monitoring」などのデータベース・トラッキング・ツールを使用する。 (ご使用のデータベース・システムの資料を参照してください。)