グローバルセッションの管理
セッションのデフォルトの挙動を変更するには、Zend_Session
の静的メソッドを使用します。グローバルセッションの管理や操作には、すべて
Zend_Session を使用します。たとえば
»
ext/session のオプション
を設定するには、 Zend_Session::setOptions() を使用します。
また、安全な 設定オプションセッション名前空間が要求されると、事前に Zend_Session::start() で開始されていない場合には Zend_Session が自動的にセッションを開始します。 もととなる PHP セッションの設定は Zend_Session のデフォルトを使用します。これを変更するには、事前に Zend_Session::setOptions() を使用して設定しておきます。
オプションを指定するには、そのベース名 (" Example #1 Zend_Config による Zend_Session の設定 このコンポーネントを Zend_Config_Ini で設定するには、まず設定オプションを INI ファイルに追加します。
次に、この設定ファイルを読み込んで、その内容を配列として Zend_Session::setOptions() に渡します。
上の例であげたほとんどのオプションについては、 PHP のドキュメントで説明されているので、ここでの説明は不要でしょう。 しかし、いくつか重要なものについては説明しておきます。
エラー: すでに送信されたヘッダ"Cannot modify header information - headers already sent" や "You must call .. before any output has been sent to the browser; output started in ..." のようなエラーが出た場合は、そのメッセージの直接の原因となった部分 (関数あるいはメソッド) がどこなのかをきちんと調べましょう。 HTTP ヘッダを送信するアクション、たとえばブラウザのクッキーの変更などは、 通常の出力 (バッファリングされていない出力) の前に行う必要があります。ただし PHP の出力バッファリングを使用している場合は例外です。
セッション識別子
導入: Zend Framework でセッションを用いる際の最も推奨される方法は、
ブラウザのクッキー (ブラウザに保存される、通常のクッキー)
を使用することです。個々のユーザを追跡するために、一意な識別子を
URL に埋め込むことは、お勧めしません。
デフォルトでは、このコンポーネントは、
クッキーのみを使用してセッション識別子を管理しています。
クッキーの値が、ブラウザのセッションの一意な識別子となります。
PHP の ext/session は、この識別子を使用して
ウェブサイトの訪問者との一対一の対応を保持し、
それぞれの訪問者ごとのセッションデータを持続して保持します。
Zend_Session* は、この保存の仕組み ( なぜ?: 攻撃者にセッション識別子を知られてしまうと、 その攻撃者は別のユーザ (犠牲者) になりすますことができるようになります。 そして、その犠牲者にしかアクセスできない情報を取得したり、 犠牲者のデータを操作したりといったことが あなたのアプリケーションから行えるようになってしまうのです。 セッション ID を変更することで、セッションハイジャックを防ぐことができます。 セッション ID を変更した後は、変更後の値が攻撃者に知られない限り 攻撃者は新しいセッション ID を使用できません。その結果、 訪問者のセッションをのっとることができなくなります。 仮に攻撃者が古いセッション ID を取得したとしても、 regenerateId() はセッションデータを古いセッション ID から新しいほうに移すので、古いセッション ID からはどのデータにもアクセスできなくなります。 いつ regenerateId() を使うのか?: Zend_Session::regenerateId() を Zend Framework の起動ファイルに追加するのが、もっとも安全かつ確実に ユーザエージェントのクッキーにあるセッション ID を再生成する方法です。 セッション ID をいつ再生成するのかについての条件判断がない場合は、 ここに追加しておくとよいでしょう。 リクエストのたびに再生成するようにしておくと攻撃パターンのいくつかを防げますが、 中にはそれによるパフォーマンスの劣化やネットワーク帯域への負荷がきになる人もいるでしょう。 そこで、アプリケーション内でリスクの大きそうなところがどこかを判断し、 その場面でだけセッション ID を再生成するということも一般に行われています。 ウェブサイト訪問者のセッションの権限が「格上げされる」 (自分の "プロフィール" を編集する前に再度認証を行うなど) 際や、セキュリティ上「重要な」パラメータが変更される際などには、 常に regenerateId() で新しいセッション ID を作成するようにしましょう。 rememberMe() 関数をコールする際には、内部で自動的に regenerateId() がコールされます。 ユーザがウェブサイトへのログインに成功したら、 regenerateId() の代わりに rememberMe() を使うようにしましょう。 セッションハイジャックおよびセッション固定化
»
クロスサイトスクリプト (XSS) 脆弱性
を避けることは、セッションハイジャックを防ぐ助けになります。
» Secunia の統計
によると、XSS 問題は頻繁に発生します。これは、
ウェブアプリケーションの開発言語が何であっても同じです。
XSS 問題が決して起こらないことを期待するよりも、
もしそれが発生した場合の被害を最小限に抑える方法を考えましょう。
XSS があれば、攻撃者は犠牲者のネットワークトラフィックに
直接アクセスする必要がなくなります。
犠牲者がすでにセッションクッキーを取得している場合、
Javascript XSS があると攻撃者がそのクッキーを読み取り、
セッションを盗むことができるようになります。
犠牲者がまだセッションクッキーを持っていない場合は、
攻撃者は XSS を使用して Javascript を注入し、
犠牲者のブラウザに既知の値のセッション ID クッキーを作成します。
そして同じクッキーを攻撃者のシステムに設定し、
犠牲者のセッションをのっとります。
犠牲者が攻撃者のウェブサイトを訪問すると、攻撃者は
犠牲者のユーザエージェントに関するその他の特性もエミュレートできるようになります。
あなたの作成するウェブサイトに XSS 脆弱性があると、
攻撃者はそこに AJAX Javascript を仕込み、知らないうちに攻撃者のウェブサイトを
「訪問」させてしまうことが可能になります。
攻撃者はそれによって犠牲者のブラウザの特性を取得し、
改ざんされたセッションでウェブサイトにアクセスするようになります。
しかし、開発者が
それ単体では、セッションを最初に使用する際に
Zend_Session::regenerateId()
をコールしてもセッション固定化攻撃は防げません。そのセッションが、
攻撃者によって偽装されたものであるかどうかを判別できる必要があります。
先ほど説明したこととは矛盾しているように感じられるかもしれません。
しかしここで、攻撃者自身が
まず最初にあなたのウェブサイトのセッションを開始した場合のことを考えてみましょう。
セッションを "最初に使用" するのは攻撃者です。
すると彼は、( regenerateId() による) 初期化の結果を知ることになります。
その後、攻撃者や新しいセッション ID と XSS 脆弱性を組み合わせて使用するか、
あるいは自分のウェブサイトにそのセッション ID
を使用したリンクを埋め込みます
(これは、 同じセッション ID を使用している場合に 攻撃者と犠牲者を区別することができれば、 セッションハイジャックを直接行うことはできなくなります。 しかし、そのような区別を行うと、ユーザビリティが犠牲になってしまうことがあります。 区別するための方法が明確ではないからです。 たとえば、最初にセッションが作成されたときとは別の国に属する IP アドレスからリクエストを受け取った場合、 そのリクエストはおそらく攻撃者からのものだと考えられます。 しかし、次のような条件のもとでは、ウェブサイトへのアクセスが 犠牲者からのものなのか攻撃者からのものなのかを区別する方法はありません。
Example #2 セッション固定化 rememberMe(integer $seconds)
通常は、セッションが終わるのはユーザエージェントが終了したとき、
つまりユーザがウェブブラウザと閉じたときです。
しかし、アプリケーション側で、ブラウザを閉じた後でもユーザセッションを有効にしておくこともできます。
この機能を実現するには、持続クッキーを使用します。
セッションの開始前に Zend_Session::rememberMe()
を使用すると、セッションクッキーの有効期限を制御できます。
秒数を指定しなかった場合は、セッションクッキーの持続期間はデフォルトの
forgetMe()この関数は rememberMe() を補完するものです。 セッションクッキーの有効期限を変更し、 ユーザエージェントのセッションが終了したときに有効期限が切れるようにしたものを書き込みます。 sessionExists()このメソッドを使用して、現在のユーザエージェント/リクエスト に対応するセッションが既に存在するかどうかを調べます。 これはセッションを開始する前に使用します。その他の Zend_Session および Zend_Session_Namespace のメソッドとは独立しています。 destroy(bool $remove_cookie = true, bool $readonly = true)
Zend_Session::destroy() は、
現在のセッションに関連付けられているすべての持続的データを破棄します。
しかし、PHP の変数の値は何の影響も受けません。
したがって、名前空間つきのセッション
(Zend_Session_Namespace のインスタンス)
は読み込み可能な状態のままです。
「ログアウト」を行うには、オプションのパラメータを TRUE
(デフォルト) に設定し、
ユーザエージェントのセッション ID クッキーを削除します。
オプションのパラメータ "Cannot modify header information - headers already sent" というエラーが出た場合は、最初の引数として TRUE (セッションクッキーを削除) を使用しないようにするか、あるいは このセクションを参照してください。 つまり、 Zend_Session::destroy(true) をコールするなら PHP が HTTP ヘッダを送信する前にするか、 あるいは出力バッファリングを有効にしなければなりません。 また、出力データの大きさが、設定したバッファサイズをこえてはいけません。 これにより、 destroy() のコール前に出力が送信されてしまうことを防ぎます。
stop()このメソッドは、単に Zend_Session のフラグを切り替え、 セッションデータへの書き込みをできないようにするだけのものです。 その他どのような機能を実装するかについては、フィードバックを受付中です。 潜在的な使用法としては、一時的に Zend_Session_Namespace インスタンスや Zend_Session のメソッドから セッションデータに書き込めなくすることがあります。 この場合、実行はビュー関連のコードに移譲されます。 これらのインスタンスやメソッドからの書き込みを含むアクションは、 例外をスローします。 writeClose($readonly = true)
セッションを終了して内容を書き込んだ後に、
|
高度な使用法 |