mirror of
https://github.com/php/doc-ja.git
synced 2026-03-24 07:02:08 +01:00
795 lines
41 KiB
XML
795 lines
41 KiB
XML
<?xml version="1.0" encoding="utf-8"?>
|
|
<!-- $Revision$ -->
|
|
<!-- EN-Revision: 55e0481a24fd4d7db21b62f1885973edbca25e60 Maintainer: mumumu Status: ready -->
|
|
|
|
<chapter xml:id="session.security" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
<title>セッション と セキュリティ</title>
|
|
<para>
|
|
外部リンク: <link xlink:href="&url.session-fixation;">Session fixation</link>
|
|
</para>
|
|
<para>
|
|
HTTP におけるセッション管理は、web セキュリティのコアに相当します。
|
|
セッションがセキュアであることを保証するために、
|
|
全てのとりうる軽減策を採用<emphasis>すべき</emphasis>です。
|
|
開発者はまた、適用可能なセキュリティ対策を 有効/実行 すべきです。
|
|
</para>
|
|
|
|
<sect1 xml:id="features.session.security.management">
|
|
<title>セッション管理の基礎</title>
|
|
|
|
<sect2 xml:id="features.session.security.management.basic">
|
|
<title>セッションのセキュリティ</title>
|
|
|
|
<para>
|
|
セッションモジュールは、セッションに保存された情報を
|
|
作成したユーザーだけが見られることを保証できません。
|
|
セッションに紐付けられた値によっては、
|
|
セッションの機密性を守るために追加の対策が必要です。
|
|
</para>
|
|
|
|
<para>
|
|
セッションに保存されているデータがどれくらい重要かを評価し、
|
|
さらなる防御策を展開すべきかもしれません。
|
|
通常、そうしてしまうとコストが高く付きます。
|
|
たとえば、ユーザーの利便性を損なうことが挙げられます。
|
|
たとえば、ユーザーを単純なソーシャルエンジニアリングから守るためには、
|
|
<link linkend="ini.session.use-only-cookies">session.use_only_cookies</link> を有効にする必要があります。
|
|
この場合、クッキーを無条件にクライアント側でも有効にしなければなりません。
|
|
さもないとセッションが動作しないからです。
|
|
</para>
|
|
|
|
<para>
|
|
既存のセッションIDをサードパーティに漏らす方法は複数あります。
|
|
JavaScriptインジェクション、セッションID を URL に埋め込む方法、
|
|
パケット盗聴、デバイスへの物理アクセス、などです。
|
|
セッションIDが漏れてしまうと、
|
|
サードパーティがその特定のIDに紐付けられた全てのリソースに
|
|
アクセスできるようになってしまいます。
|
|
|
|
既存のセッションIDを漏らす最初の方法は、URL でセッションIDを持ち回すやり方です。
|
|
もし外部サイトやリソースへのリンクが存在したとすると、
|
|
セッションIDを含むURLが、外部サイトのリファラログに保存されるかもしれません。
|
|
ふたつめは、より積極的な攻撃者がネットワークトラフィックを盗聴しているかもしれません。
|
|
ネットワークトラフィックが暗号化されていないと、
|
|
セッションIDがネットワーク越しにプレーンテキスト内に流出してしまいます。
|
|
防御策は、SSL/TLS をサーバー側で実装し、ユーザーがそれを使うように強制することです。
|
|
HSTS も、セキュリティを向上させるために使えるはずです。
|
|
</para>
|
|
|
|
<note>
|
|
<simpara>
|
|
HTTPS でさえも、あらゆる時に機密データを保護することはできません。
|
|
たとえば、CRIME や Beast 脆弱性が、攻撃者にデータを読めるようにしてしまうかもしれません。
|
|
また、多くのネットワークは HTTPS の MITMプロキシ を監査の目的で採用しています。
|
|
攻撃者も、そうしたプロキシをセットアップしているかもしれません。
|
|
</simpara>
|
|
</note>
|
|
|
|
</sect2>
|
|
|
|
<sect2 xml:id="features.session.security.management.non-adaptive-session">
|
|
<title>セッションアダプションを防ぐためのセッション管理</title>
|
|
|
|
<para>
|
|
PHP のセッションマネージャーは、
|
|
現状ではデフォルトでセッションアダプション攻撃が可能です。
|
|
アダプション攻撃が可能なセッションマネージャーは、
|
|
追加のリスクを背負うことになります。
|
|
</para>
|
|
|
|
<para>
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>を有効にし、かつセッションの保存ハンドラがサポートしている場合、
|
|
初期化されていないセッションIDは拒否され、新しいものが作成されます。
|
|
これによって、攻撃者がユーザーに既知のセッションIDを強制的に使わせることを防止できます。
|
|
攻撃者はセッションID付きのリンクをペーストしたり、
|
|
そうしたリンクを含んだメールを送るかもしれません。
|
|
たとえば <literal>http://example.com/page.php?PHPSESSID=123456789</literal> のようなものです。
|
|
<link linkend="ini.session.use-trans-sid">session.use_trans_sid</link> が有効な場合、
|
|
ユーザーは攻撃者が提供したセッションIDを使ってセッションを開始してしまいます。
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link> は、
|
|
こうしたリスクを軽減します。
|
|
</para>
|
|
|
|
<warning>
|
|
<simpara>
|
|
ユーザー定義の保存ハンドラも、セッションIDの検証を行うことで
|
|
厳格なセッションモードをサポートできます。
|
|
保存ハンドラを定義した全てのユーザーは、セッションIDの検証を実装すべきです。
|
|
</simpara>
|
|
</warning>
|
|
|
|
<para>
|
|
セッションIDクッキーは、domain, path, httponly, secure, そして
|
|
PHP 7.3 以降では、SameSite 属性とともに設定できます。
|
|
これは、ブラウザで定義されたものが優先します。
|
|
この優先される仕組みを使い、攻撃者は永久に使えるセッションIDを設定できてしまいます。
|
|
<link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>
|
|
はこの問題を解決できません。
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
|
|
を使うとこのリスクを軽減できます。
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>=On にすると、
|
|
初期化されていないセッションIDは拒否されます。
|
|
</para>
|
|
|
|
<note>
|
|
<simpara>
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
|
|
はアダプション可能なセッション管理機構のリスクを軽減しますが、
|
|
攻撃者は自らが生成したセッションIDを、
|
|
初期化済みセッションIDとして使わせることが出来てしまいます。
|
|
たとえば JavaScriptインジェクション攻撃です。
|
|
この攻撃はこのマニュアルで推奨する方法で軽減できます。
|
|
</simpara>
|
|
|
|
<simpara>
|
|
このマニュアルに従い、開発者は
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
|
|
を有効にし、タイムスタンプベースのセッション管理を行い、
|
|
推奨する手続きを使って <function>session_regenerate_id</function> を使い
|
|
セッションIDの再生成を行うべきです。
|
|
開発者が上記全てに従えば、攻撃者が生成したセッションIDは、結局は削除されます。
|
|
</simpara>
|
|
|
|
<simpara>
|
|
有効期限が切れたセッションにアクセスされたときのために、
|
|
開発者は全てのアクティブなユーザーのセッションデータを保存すべきです。
|
|
この情報は後に行われる調査とも関係があります。
|
|
ユーザーは全てのセッションから強制的にログアウトさせられるべきです。
|
|
つまり、再認証させるべきです。
|
|
こうすることで、攻撃者が盗まれたセッションを悪用することを防止できます。
|
|
</simpara>
|
|
</note>
|
|
|
|
<warning>
|
|
<simpara>
|
|
有効期限が切れたセッションにアクセスすることが、
|
|
必ずしも攻撃であることを示しているとは限りません。
|
|
不安定なネットワークや、
|
|
アクティブなセッションをすぐに削除してしまったりすることが原因で、
|
|
正当なユーザーが、有効期限が切れたセッションにアクセスすることがあるからです。
|
|
</simpara>
|
|
</warning>
|
|
|
|
<para>
|
|
PHP 7.1.0 以降、<function>session_create_id</function> が追加されました。
|
|
この関数は、セッションIDの前にユーザー定義のIDをつけることで、
|
|
全てのアクティブなユーザーのセッションに効率的にアクセスできます。
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
|
|
を有効にすることが重要です。有効にしないと、
|
|
悪意のあるユーザーが悪意のあるセッションIDを他のユーザーに設定できてしまいます。
|
|
</para>
|
|
|
|
<note>
|
|
<simpara>
|
|
PHP 7.1.0 より前のバージョンのユーザーは新しいセッションIDを生成する
|
|
のに <acronym>CSPRNG</acronym>、
|
|
つまり <filename>/dev/urandom</filename> や <function>random_bytes</function>
|
|
やハッシュ関数を使う<emphasis>べき</emphasis> です。
|
|
<function>session_create_id</function> には衝突を検出する機能があり、
|
|
セッションの INI 設定に従ってセッションIDを生成します。
|
|
<function>session_create_id</function> の利用が好ましいです。
|
|
</simpara>
|
|
</note>
|
|
|
|
</sect2>
|
|
|
|
<sect2 xml:id="features.session.security.management.session-id-regeneration">
|
|
<title>セッションID の再生成</title>
|
|
|
|
<para>
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
|
|
は良い軽減策ですが、十分ではありません。開発者はセッションのセキュリティのために
|
|
<function>session_regenerate_id</function> を同時に使うべきです。
|
|
</para>
|
|
|
|
<para>
|
|
セッションIDを再生成すると、盗まれたセッションIDを使われるリスクが減らせるので、
|
|
<function>session_regenerate_id</function> 関数は定期的に呼び出されなければなりません。
|
|
たとえば、セキュリティに敏感な内容を扱っているのなら、
|
|
セッションIDを15分毎に再生成するようにしてください。
|
|
セッションID が盗まれた場合でも、正当なユーザーと攻撃者のセッションは両方時間切れになります。
|
|
言い換えれば、ユーザーだろうと攻撃者のアクセスだろうと、
|
|
期限切れのセッションにアクセスしたとしてエラーになるのです。
|
|
</para>
|
|
|
|
<para>
|
|
セッションID はユーザーの権限が上昇したときは再生成されなければ <emphasis>なりません</emphasis>。
|
|
たとえば認証が成功した後などです。
|
|
<function>session_regenerate_id</function> は、
|
|
認証情報を <varname>$_SESSION</varname> に設定する前に必ずコールされなければなりません。
|
|
(<function>session_regenerate_id</function> は
|
|
タイムスタンプなどを保存するために、現在のセッションにセッションデータを自動的に保存します)
|
|
必ず新しいセッションだけに、認証済みのフラグが含まれるようにしてください。
|
|
</para>
|
|
|
|
<para>
|
|
開発者は
|
|
<link linkend="ini.session.gc-maxlifetime">session.gc_maxlifetime</link>
|
|
によるセッションの期限切れに依存しては <emphasis>いけません</emphasis>。
|
|
攻撃者は、認証済みのセッションも含めて、期限切れを防いで悪用を続けるため、
|
|
ターゲットのセッションIDに定期的にアクセスしている可能性があるからです。
|
|
</para>
|
|
|
|
<para>
|
|
そのかわりに、開発者はタイムスタンプベースのセッション管理を実装しなければなりません。
|
|
</para>
|
|
|
|
<warning>
|
|
<simpara>
|
|
セッションマネージャーはタイムスタンプを透過的に管理できますが、
|
|
この機能はまだ実装されていません。
|
|
古いセッションデータは GC されるまで保持されなければなりません。
|
|
同時に、開発者は期限切れになったセッションデータが削除されることを保証しなければなりません。
|
|
たとえば、<code>session_regenerate_id(true);</code> と
|
|
<function>session_destroy</function> をアクティブなセッションに対して同時に呼んでは絶対にいけません。
|
|
これは矛盾したように聞こえますが、これは必須条件です。
|
|
</simpara>
|
|
</warning>
|
|
|
|
<para>
|
|
<function>session_regenerate_id</function> は、
|
|
デフォルトで期限切れのセッションを削除 <emphasis>しません</emphasis>。
|
|
期限切れの認証済みのセッションが存在するかもしれません。
|
|
開発者は期限切れのセッションは、誰からも消費されないようにしなければなりません。
|
|
期限切れのセッションデータへのアクセスを、タイムスタンプを使うことで禁止すべきです。
|
|
</para>
|
|
|
|
<warning>
|
|
<simpara>
|
|
アクティブなセッションを突然削除すると、望まない副作用が起きます。
|
|
Webアプリケーションへの同時接続が起きた かつ/または
|
|
ネットワークが不安定な場合に、セッションが突然消える可能性があります。
|
|
</simpara>
|
|
<simpara>
|
|
アクティブなセッションが突然消えてしまうと、
|
|
悪意のあるアクセスの可能性を検出することができなくなります。
|
|
</simpara>
|
|
<simpara>
|
|
期限切れのセッションを突然削除するのではなく、
|
|
開発者は短い期限切れの時間(タイムスタンプ)を <varname>$_SESSION</varname>
|
|
に設定し、セッションデータにアクセスすることを自分で禁止すべきです。
|
|
</simpara>
|
|
<simpara>
|
|
開発者は <function>session_regenerate_id</function> を呼び出した後すぐに、
|
|
古いセッションデータへのアクセスを禁止してはいけません。
|
|
その後の段階で禁止しなければなりません。
|
|
たとえば、有線ネットワークのような安定したネットワークは数秒後、
|
|
無線LAN や携帯電話のような不安定なネットワークの場合は、2, 3分後です。
|
|
</simpara>
|
|
<simpara>
|
|
ユーザーのアクセスが期限切れのセッションだった場合、
|
|
アクセスを拒否するべきです。攻撃されている可能性があるすべてのユーザーから、
|
|
認証済みのステータスを削除することも推奨します。
|
|
</simpara>
|
|
</warning>
|
|
|
|
<para>
|
|
<link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>
|
|
と <function>session_regenerate_id</function> を適切に使うことで、
|
|
攻撃者によって設定された、削除できないクッキーを伴うDOSが発生することがあります。
|
|
この場合、開発者はユーザーに Cookie を削除させ、
|
|
セキュリティ上の問題に晒されていることを教えることができます。
|
|
攻撃者は、脆弱なWebアプリケーションや
|
|
ウイルスに感染したブラウザのプラグイン、
|
|
物理的に侵害されたデバイスなどを経由して悪意のあるCookieを設定している可能性があります。
|
|
</para>
|
|
|
|
<warning>
|
|
<simpara>
|
|
DOS のリスクを誤解しないでください。
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>=On
|
|
は一般的なセッションIDのセキュリティには必須です!
|
|
全てのサイトが <link linkend="ini.session.use-strict-mode">session.use_strict_mode</link> を有効にすることをお勧めします。
|
|
</simpara>
|
|
<simpara>
|
|
DOS はアカウントが攻撃されている場合にだけ発生する可能性があります。
|
|
アプリケーションに存在する JavaScript インジェクションの脆弱性がもっともよくある原因です。
|
|
</simpara>
|
|
</warning>
|
|
|
|
</sect2>
|
|
|
|
<sect2 xml:id="features.session.security.management.session-data-deletion">
|
|
<title>セッションデータを削除する</title>
|
|
|
|
<para>
|
|
期限切れのセッションデータは、アクセス不能にし、削除しなければなりません。
|
|
現状のセッションモジュールはこの機能をうまく扱えません。
|
|
</para>
|
|
|
|
<para>
|
|
期限切れのセッションデータは、できるだけ早く削除すべきです。
|
|
しかしながら、アクティブなセッションは、すぐに削除してはいけません。
|
|
これらの要求を満たすためには、
|
|
開発者はタイムスタンプベースのセッション管理を自分自身で実装する必要があります。
|
|
</para>
|
|
|
|
<para>
|
|
期限切れのタイムスタンプを $_SESSION に設定し、管理します。
|
|
期限切れのセッションデータへのアクセスは禁止します。
|
|
期限切れのセッションデータへのアクセスが検出された場合、
|
|
そのユーザーのセッションから認証済みのステータスを全て取り除き、
|
|
強制的に再認証させることをおすすめします。
|
|
期限切れのセッションデータへのアクセスは、攻撃されている可能性があります。
|
|
これを実現するために、
|
|
開発者はユーザーごとに全てのアクティブなセッションを追跡しなければなりません。
|
|
</para>
|
|
|
|
<note>
|
|
<simpara>
|
|
期限切れのセッションへのアクセスは、ネットワークが不安定だったり、
|
|
Webサイトへの同時アクセスも原因で起こりえます。
|
|
たとえば、サーバーは新しいセッションIDを Cookie 経由で設定しようとしたが、
|
|
接続が失われたため Set-Cookie のパケットが
|
|
クライアントに届かなかったりする可能性があります。
|
|
ある接続で、<function>session_regenerate_id</function> によって新しいセッションIDが発行されたけれども、
|
|
別の同時接続が、まだ新しいセッションIDを受け取っていない可能性もあります。
|
|
よって、開発者は期限切れのセッションへのアクセスを後の段階で禁止しなければなりません。
|
|
すなわち、タイムスタンプベースのセッション管理が必須なのです。
|
|
</simpara>
|
|
</note>
|
|
|
|
<para>
|
|
まとめると、セッションデータは
|
|
<function>session_regenerate_id</function> や <function>session_destroy</function>
|
|
を使って破棄してはいけません。
|
|
むしろ、セッションデータへのアクセスを制御するためにタイムスタンプを使わなければなりません。
|
|
<function>session_gc</function> 関数に、
|
|
セッションデータストレージから、期限切れのデータを削除させましょう。
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 xml:id="features.session.security.management.session-locking">
|
|
<title>Session とロック</title>
|
|
|
|
<para>
|
|
セッションデータはレースコンディションを避けるため、デフォルトでロックされます。
|
|
ロックを掛けることは複数のリクエスト間でセッションデータの一貫性を保つため、必須です。
|
|
</para>
|
|
|
|
<para>
|
|
しかしながら、セッションをロックしてしまうと、
|
|
攻撃者がDOS攻撃に悪用する可能性があります。
|
|
セッションをロックすることによるDOS攻撃のリスクを軽減するためには、
|
|
ロックを最小限にすることです。
|
|
セッションデータを更新する必要がないときは、読み取り専用のセッションを使うようにします。
|
|
<code>session_start(['read_and_close'=>1]);</code>
|
|
$_SESSION を更新した後は、<function>session_commit</function> を使って
|
|
できるだけ早くセッションを閉じるようにします。
|
|
</para>
|
|
|
|
<para>
|
|
現状のセッションモジュールは、
|
|
セッションがアクティブでない時に $_SESSION が変更されたかを検知 <emphasis>しません</emphasis>。
|
|
セッションがアクティブでない時に $_SESSION を変更しないことは、開発者の責任です。
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 xml:id="features.session.security.management.active-sessions">
|
|
<title>アクティブなセッション</title>
|
|
|
|
<para>
|
|
開発者は、ユーザーごとにアクティブなセッションを追跡し続けるべきです。
|
|
そして、アクティブなセッションの数がどれくらいあるかや、
|
|
どのIP(や地域) からかとか、どのくらいの期間アクティブなのか、などです。
|
|
PHP はこれらを追跡しません。開発者が行うことが想定されています。
|
|
</para>
|
|
|
|
<para>
|
|
これを実装するやり方はたくさんあります。
|
|
ひとつの可能な実装は、データベースをセットアップして必須のデータを追跡し、
|
|
関連するあらゆる情報を保存することです。
|
|
セッションデータは GC されるので、開発者はアクティブなセッションのデータベースが一貫性を保つように
|
|
GC されたデータに注意を払わなければなりません。
|
|
</para>
|
|
|
|
<para>
|
|
一番簡単な実装は、"ユーザーIDをセッションIDの前に付ける" ことで、
|
|
必須の情報を $_SESSION に保存することです。
|
|
多くのデータベースは文字列の prefix を選択するのに良いパフォーマンスを発揮します。
|
|
開発者は <function>session_regenerate_id</function> と
|
|
<function>session_create_id</function> をこの目的で使うこともできます。
|
|
</para>
|
|
|
|
<warning>
|
|
<simpara>
|
|
秘密のデータを prefix に絶対に使わないでください。
|
|
ユーザーIDが秘密の場合、<function>hash_hmac</function> を使うことも検討しましょう。
|
|
</simpara>
|
|
</warning>
|
|
|
|
<warning>
|
|
<simpara>
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>
|
|
はこの場合に必須です。必ず有効にするようにしてください。
|
|
そうしなければ、アクティブなセッションデータベースが侵害される可能性があります。
|
|
</simpara>
|
|
</warning>
|
|
|
|
<para>
|
|
タイムスタンプベースのセッション管理は、時間切れのセッションへのアクセスを検知するのに必須です。
|
|
時間切れのセッションへのアクセスが検知された場合、
|
|
そのユーザーの全てのアクティブなセッションから認証済みのフラグを削除すべきです。
|
|
こうすることで、攻撃者が盗んだセッションを悪用し続けることを防げます。
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 xml:id="features.session.security.management.session-and-autologin">
|
|
<title>Session と自動ログイン</title>
|
|
|
|
<para>
|
|
開発者は有効期間が長いセッションを、自動ログインに使ってはいけません。
|
|
なぜなら、セッションが盗まれるリスクが増えるからです。
|
|
自動ログイン機能は、開発者が実装すべきです。
|
|
</para>
|
|
|
|
<para>
|
|
<function>setcookie</function> を使い、
|
|
セキュアなワンタイムハッシュを自動ログインのキーとして使います。
|
|
SHA-2 より強いセキュアなハッシュを使います。
|
|
たとえば、 <function>random_bytes</function> や <filename>/dev/urandom</filename> で生成したランダムデータを
|
|
SHA-256 またはそれより強いハッシュ関数と一緒に使います。
|
|
</para>
|
|
|
|
<para>
|
|
ユーザーが認証されていなかったら、ワンタイムの自動ログインキーが有効かどうかをチェックします。
|
|
もし、キーが正しければ、ユーザーを認証し、新しいセキュアなワンタイムハッシュキーを設定します。
|
|
自動ログインキーを使うのは一度きりです。つまり、再利用してはいけません。
|
|
常に新しいものを生成するようにします。
|
|
</para>
|
|
|
|
<para>
|
|
自動ログインのキーが長期間有効な認証キーである場合、
|
|
できるだけ手厚く保護すべきです。
|
|
path/httponly/secure/SameSite クッキー属性をセキュアにするために使います。
|
|
つまり、自動ログインキーを必要ないのに送信しないでください。
|
|
</para>
|
|
|
|
<para>
|
|
開発者は自動ログインを無効にする機能や、
|
|
不要な自動ログインのキーを削除する機能を実装しなければなりません。
|
|
</para>
|
|
|
|
</sect2>
|
|
|
|
<sect2 xml:id="features.session.security.management.csrf">
|
|
<title>CSRF (Cross-Site Request Forgeries) 攻撃</title>
|
|
|
|
<para>
|
|
セッションと認証は、CSRF 攻撃を防ぐことはありません。
|
|
開発者は CSRF への防御を自分で実装しなければなりません。
|
|
</para>
|
|
|
|
<para>
|
|
CSRF 攻撃を防ぐために、
|
|
<function>output_add_rewrite_var</function> 関数が使えます。
|
|
詳細はマニュアルページを参照ください。
|
|
</para>
|
|
|
|
<note>
|
|
<simpara>
|
|
PHP 7.2.0 より前のバージョンでは、この関数は trans sid と同じ出力バッファとINI 設定を使っていました。
|
|
よって、PHP 7.2.0 より前のバージョンで
|
|
<function>output_add_rewrite_var</function> を使うことはおすすめしません。
|
|
</simpara>
|
|
</note>
|
|
|
|
<para>
|
|
ほとんどの Webアプリケーションフレームワークは、CSRF から防御する機能をサポートしています。
|
|
詳細は、Webアプリケーションフレームワークのマニュアルを参照ください。
|
|
</para>
|
|
|
|
<para>
|
|
PHP 7.3 以降では、セッションクッキーにSameSite 属性が設定できます。
|
|
この属性も、CSRF 脆弱性を軽減できる追加の対策になります。
|
|
</para>
|
|
</sect2>
|
|
</sect1>
|
|
|
|
<sect1 xml:id="session.security.ini">
|
|
<title>セッションに関連する INI 設定をセキュアにする</title>
|
|
|
|
<para>
|
|
セッション関連のINI設定をセキュアにすることで、
|
|
開発者はセッションのセキュリティを改善できます。
|
|
重要な INI 設定であっても、推奨される設定がないものがあります。
|
|
開発者にはセッションの設定を強固にする責任があります。
|
|
</para>
|
|
|
|
<itemizedlist>
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.cookie-lifetime">session.cookie_lifetime</link>=0
|
|
</para>
|
|
<para>
|
|
<literal>0</literal> には特別な意味があります。
|
|
これは、恒久的なストレージにクッキーを保存しないようブラウザに指示します。
|
|
よって、ブラウザが終了した場合、セッションIDクッキーはすぐに削除されます。
|
|
開発者がこの値を0以外にすると、他のユーザーがセッションIDを使うことを許す可能性があります。
|
|
このため、ほとんどのWebアプリケーションは、"<literal>0</literal>" を使うべきです。
|
|
</para>
|
|
<para>
|
|
自動ログイン機能が必須の場合、
|
|
開発者は自前のセキュアな自動ログイン機能を実装しなければなりません。
|
|
この機能のために、有効期間が長いセッションIDを使ってはいけません。
|
|
前のページの関連するセクションで、より多くの情報が見つかるかもしれません。
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.use-cookies">session.use_cookies</link>=On
|
|
</para>
|
|
<para>
|
|
<link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>=On
|
|
</para>
|
|
<para>
|
|
HTTP クッキーはいくつか問題を抱えていますが、
|
|
クッキーはセッションIDを管理する手段として好ましい方法であり続けています。
|
|
セッションIDの管理に、可能であればクッキーだけを使うようにしましょう。
|
|
ほとんどのアプリケーションはセッションIDの管理にクッキーを使うべきです。
|
|
</para>
|
|
<para>
|
|
<link linkend="ini.session.use-only-cookies">session.use_only_cookies</link>=Off の場合、
|
|
セッションモジュールは、たとえセッションIDクッキーが未初期化であっても、
|
|
セッションIDが与えられた GET や POST によって設定されたものをセッションIDに使うようになります。
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link>=On
|
|
</para>
|
|
<para>
|
|
セッションをセキュアにするために
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link> を有効にすることは必須ですが、
|
|
デフォルトでは無効になっています。
|
|
</para>
|
|
<para>
|
|
有効にすることで、セッションモジュールが未初期化のセッションIDを使うことを防げます。
|
|
別の言い方をすると、セッションモジュールは、
|
|
セッションモジュールが生成した有効なセッションIDだけを受け入れるようになるということです。
|
|
この設定は、ユーザーによって与えられたあらゆるセッションIDを拒否します。
|
|
</para>
|
|
<para>
|
|
Cookie の仕様によって、
|
|
攻撃者はローカルにクッキーのデータベースを設定したり、
|
|
JavaScriptインジェクションの脆弱性を突くことで、
|
|
削除できないセッションIDクッキーを置くことが可能です。
|
|
<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link> によって、
|
|
攻撃者が初期化したセッションIDが使われるのを防ぐことができます。
|
|
</para>
|
|
<note>
|
|
<para>
|
|
攻撃者は自分のデバイスでセッションIDを初期化し、
|
|
ターゲットユーザーのセッションIDを設定するかもしれません。
|
|
攻撃者は悪用するセッションIDをアクティブな状態に保たなければなりません。
|
|
攻撃者はこのシナリオで攻撃を実行するには追加のステップが必要です。
|
|
よって、<link linkend="ini.session.use-strict-mode">session.use_strict_mode</link> が軽減策として役に立つのです。
|
|
</para>
|
|
</note>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.cookie-httponly">session.cookie_httponly</link>=On
|
|
</para>
|
|
<para>
|
|
セッションクッキーを JavaScript からアクセスさせることを拒否します。
|
|
この設定によって、JavaScriptインジェクションによってクッキーを盗むことを防げます。
|
|
</para>
|
|
<para>
|
|
セッションIDをCSRFトークンとして使うことも可能ですが、
|
|
推奨されません。たとえば、HTMLソースが保存され、他のユーザに送られることがあるからです。
|
|
開発者は、セキュリティを向上させるため、セッションIDをWebサイトに出力すべきではありません。
|
|
ほとんどのアプリケーションは、httponly 属性をセッションIDクッキーに設定しなければなりません。
|
|
</para>
|
|
<note>
|
|
<para>
|
|
CSRF トークンも、セッションIDと同じように定期的に更新すべきです。
|
|
</para>
|
|
</note>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.cookie-secure">session.cookie_secure</link>=On
|
|
</para>
|
|
<para>
|
|
セッションIDクッキーを、プロトコルがHTTPSの場合にだけアクセスすることを許可します。
|
|
website が HTTPS 経由でのみアクセス可能であるなら、この設定を有効にすべきです。
|
|
</para>
|
|
<para>
|
|
HTTPS 経由でのみアクセス可能なWebサイト向けに、HSTS も検討すべきです。
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.cookie-samesite">session.cookie_samesite</link>="Lax" または
|
|
<link linkend="ini.session.cookie-samesite">session.cookie_samesite</link>="Strict"
|
|
</para>
|
|
<para>
|
|
PHP 7.3 以降では、セッションIDクッキー向けに <literal>"SameSite"</literal> 属性が設定できます。
|
|
この属性は、CSRF (Cross Site Request Forgery) 攻撃を軽減する手段です。
|
|
</para>
|
|
<para>
|
|
Lax と Strict の違いは、
|
|
HTTP GETリクエストを使う別の登録可能なドメインへのリクエストに対して、クッキーへのアクセスを許可するかどうかです。
|
|
Lax を使っているクッキーは別の登録可能なドメインへのGETリクエストからアクセス可能ですが、
|
|
Strict を使っているクッキーはそうではありません。
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.gc-maxlifetime">session.gc_maxlifetime</link>=[choose smallest possible]
|
|
</para>
|
|
<para>
|
|
<link linkend="ini.session.gc-maxlifetime">session.gc_maxlifetime</link>
|
|
は期限切れのセッションIDを削除する設定です。
|
|
この設定に依存することは推奨<emphasis>しません</emphasis>。
|
|
開発者はタイムスタンプを使って、セッションの有効期間を自前で管理すべきです。
|
|
</para>
|
|
<para>
|
|
セッションGC(ガベージコレクション)は、
|
|
<function>session_gc</function> を使って行うのが最適です。
|
|
<function>session_gc</function> 関数は、タスクマネージャーを使って実行すべきです。
|
|
たとえば、UNIXライクなシステムだと cron が挙げられます。
|
|
</para>
|
|
<para>
|
|
GC処理はデフォルトでは確率的に行われます。
|
|
この設定は期限切れのセッションが削除されることを保証 <emphasis>しません</emphasis>。
|
|
開発者はこの設定に依存することはできませんが、
|
|
可能な限り最小の値を指定することを推奨します。
|
|
<link
|
|
linkend="ini.session.gc-probability">session.gc_probability</link>
|
|
と <link
|
|
linkend="ini.session.gc-divisor">session.gc_divisor</link> の値を、
|
|
適切な頻度で期限切れのセッションが削除されるように調整してください。
|
|
自動ログイン機能が必須の場合、開発者は自前のセキュアな自動ログイン機能を実装しなければなりません。
|
|
詳細な情報は前のページを参照ください。
|
|
自動ログイン機能のために、有効期限が長いセッションIDを絶対に使わないでください。
|
|
</para>
|
|
<note>
|
|
<para>
|
|
セッション保存ハンドラモジュールによっては、
|
|
期限切れの処理を確率ベースで行うためにこの設定を使わないものもあります。
|
|
たとえば memcached, memcache が挙げられます。
|
|
詳細については、セッション保存ハンドラのドキュメントを参照ください。
|
|
</para>
|
|
</note>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.use-trans-sid">session.use_trans_sid</link>=Off
|
|
</para>
|
|
<para>
|
|
透過的なセッションID管理を使うことは禁止されていません。
|
|
開発者は必要な場合は採用しても構いません。
|
|
しかし、透過的なセッションID管理を無効にすると、
|
|
セッションIDインジェクションやリークの可能性が排除できるので、
|
|
一般的なセッションIDのセキュリティを改善できます。
|
|
</para>
|
|
<note>
|
|
<para>
|
|
セッションIDは、ブックマークされたURLや、電子メールに埋め込まれたURLや、
|
|
保存されたHTMLソースなどから漏れる可能性があります。
|
|
</para>
|
|
</note>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.trans-sid-tags">session.trans_sid_tags</link>=[limited tags]
|
|
</para>
|
|
<para>
|
|
(PHP 7.1.0 >=) 開発者は必要ないのにHTMLタグを書き換えるべきではありません。
|
|
デフォルト値でほとんどの場合は十分です。古いPHPバージョンの場合は、
|
|
<link linkend="ini.url-rewriter.tags">url_rewriter.tags</link> を代わりに使ってください。
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.trans-sid-hosts">session.trans_sid_hosts</link>=[limited hosts]
|
|
</para>
|
|
<para>
|
|
(PHP 7.1.0 >=) この INI 設定は、
|
|
trans sid の書き換えを許可するホストをホワイトリスト形式で定義します。
|
|
信頼できないホストを絶対に追加しないでください。
|
|
セッションモジュールは、この設定が空の場合、
|
|
<literal>$_SERVER['HTTP_HOST']</literal> だけを許可します。
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.referer-check">session.referer_check</link>=[originating URL]
|
|
</para>
|
|
<para>
|
|
<link
|
|
linkend="ini.session.use-trans-sid">session.use_trans_sid</link> が有効になっている場合、
|
|
この設定はセッションIDインジェクションのリスクを減らします。
|
|
website が <literal>http://example.com/</literal> の場合、
|
|
<literal>http://example.com/</literal> を設定してください。
|
|
HTTPS ブラウザはリファラヘッダを送信しないことに注意してください。
|
|
ブラウザはリファラヘッダを設定によって送信しない可能性もあります。
|
|
よって、この設定は信頼できるセキュリティ対策ではありませんが、
|
|
この設定を使うことは推奨します。
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.cache-limiter">session.cache_limiter</link>=nocache
|
|
</para>
|
|
<para>
|
|
HTTP コンテンツを認証済みのセッションに関してはキャッシュしないようにします。
|
|
コンテンツがプライベートでない場合だけ、キャッシュを許可します。
|
|
そうしない場合、コンテンツが外部に流出する可能性があります。
|
|
<literal>"private"</literal> は、HTTPコンテンツがセキュリティに敏感なデータを含まない場合であれば採用しても構いません。
|
|
<literal>"private"</literal> は、
|
|
共有されたクライアントによってキャッシュされた、
|
|
プライベートなデータを送信する可能性があることに注意してください。
|
|
<literal>"public"</literal> は、
|
|
HTTPコンテンツがプライベートなデータを一切含んでいない場合にのみ使わなければなりません。
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.hash-function">session.hash_function</link>="sha256"
|
|
</para>
|
|
<para>
|
|
(PHP 7.1.0 <) より強いハッシュ関数は、より強いセッションIDを生成します。
|
|
ハッシュの衝突が起こる可能性は、MD5 ハッシュアルゴリズムを使っても低いですが、
|
|
開発者は SHA2 またはそれより強い sha384 や sha512 のようなハッシュアルゴリズムを使うべきです。
|
|
開発者は、十分に長い
|
|
<link linkend="ini.session.entropy-length">entropy</link>
|
|
をハッシュ関数を使うときに必ず与えなければなりません。
|
|
</para>
|
|
</listitem>
|
|
|
|
<listitem>
|
|
<para>
|
|
<link linkend="ini.session.save-path">session.save_path</link>=[どこからでも読み取り可能なディレクトリにしない]
|
|
</para>
|
|
<para>
|
|
この設定を <filename>/tmp</filename> (デフォルト) のようにどこか
|
|
らでも読み込み可能なディレクトリに設定した場合、サーバー上
|
|
の他のユーザーがこのディレクトリのファイルのリストを取得すること
|
|
により、セッションをハイジャックをすることが可能となります。
|
|
</para>
|
|
</listitem>
|
|
|
|
</itemizedlist>
|
|
</sect1>
|
|
|
|
</chapter>
|
|
|
|
<!-- Keep this comment at the end of the file
|
|
Local variables:
|
|
mode: sgml
|
|
sgml-omittag:t
|
|
sgml-shorttag:t
|
|
sgml-minimize-attributes:nil
|
|
sgml-always-quote-attributes:t
|
|
sgml-indent-step:1
|
|
sgml-indent-data:t
|
|
indent-tabs-mode:nil
|
|
sgml-parent-document:nil
|
|
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
|
|
sgml-exposed-tags:nil
|
|
sgml-local-catalogs:nil
|
|
sgml-local-ecat-files:nil
|
|
End:
|
|
vim600: syn=xml fen fdm=syntax fdl=2 si
|
|
vim: et tw=78 syn=sgml
|
|
vi: ts=1 sw=1
|
|
-->
|