セキュリティ
セキュリティクラスには、クロスサイトリクエストフォージェリ(CSRF)攻撃からサイトを保護するのに役立つメソッドが含まれています。
ライブラリの読み込み
ライブラリを読み込む唯一の目的が CSRF 保護を処理することである場合、ライブラリを手動で読み込む必要はありません。ライブラリはフィルターとして実行され、手動操作は必要ありません。
直接アクセスする必要がある場合は、サービスファイルから読み込むことができます
<?php
$security = \Config\Services::security();
クロスサイトリクエストフォージェリ (CSRF)
警告
CSRF 保護は、**POST/PUT/PATCH/DELETE** リクエストに対してのみ利用可能です。他のメソッドのリクエストは保護されません。
前提条件
CodeIgniter の CSRF 保護を使用する場合でも、以下のようにコーディングする必要があります。そうしないと、CSRF 保護がバイパスされる可能性があります。
自動ルーティングが無効になっている場合
次のいずれかを実行します
$routes->add()
を使用せず、ルートで HTTP 動詞を使用します。処理する前に、コントローラーメソッドでリクエストメソッドを確認します。
例:
if (! $this->request->is('post')) {
return $this->response->setStatusCode(405)->setBody('Method Not Allowed');
}
注意
$this->request->is() メソッドは v4.3.0 以降で使用できます。以前のバージョンでは、if (strtolower($this->request->getMethod()) !== 'post')
を使用する必要があります。
自動ルーティングが有効になっている場合
処理する前に、コントローラーメソッドでリクエストメソッドを確認します。
例:
if (! $this->request->is('post')) {
return $this->response->setStatusCode(405)->setBody('Method Not Allowed');
}
CSRF の設定
CSRF 保護の方法
警告
セッションを使用する場合は、必ずセッションベースの CSRF 保護を使用してください。Cookie ベースの CSRF 保護では、同一サイト攻撃を防ぐことはできません。詳細は GHSA-5hm8-vh6r-2cjq を参照してください。
デフォルトでは、Cookie ベースの CSRF 保護が使用されます。これは、OWASP クロスサイトリクエストフォージェリ防止チートシートの ダブル送信 Cookie です。
セッションベースの CSRF 保護を使用することもできます。これは 同期トークンパターン です。
**app/Config/Security.php** の次の設定パラメータ値を編集することで、セッションベースの CSRF 保護を使用するように設定できます
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Security extends BaseConfig
{
public $csrfProtection = 'session';
// ...
}
トークンのランダム化
BREACH のような圧縮サイドチャネル攻撃を軽減し、攻撃者が CSRF トークンを推測するのを防ぐために、トークンランダム化を設定できます(デフォルトではオフ)。
有効にすると、ランダムなマスクがトークンに追加され、スクランブルに使用されます。
**app/Config/Security.php** の次の設定パラメータ値を編集することで、有効にできます
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Security extends BaseConfig
{
public $tokenRandomize = true;
// ...
}
トークンの再生成
トークンは、送信ごとに再生成される(デフォルト)か、セッションまたは CSRF Cookie の有効期間中は同じままにすることができます。
デフォルトのトークン再生成は、より厳格なセキュリティを提供しますが、他のトークンが無効になるため、使い勝手に関する問題が発生する可能性があります(戻る/進むナビゲーション、複数のタブ/ウィンドウ、非同期アクションなど)。この動作は、**app/Config/Security.php** の次の設定パラメータ値を編集することで変更できます
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Security extends BaseConfig
{
public $regenerate = true;
// ...
}
警告
Cookie ベースの CSRF 保護を使用し、送信後に redirect()
する場合は、withCookie()
を呼び出して、再生成された CSRF Cookie を送信する必要があります。詳細は リダイレクト を参照してください。
注意
v4.2.3 以降、Security::generateHash()
メソッドを使用して CSRF トークンを手動で再生成できます。
失敗時のリダイレクト
v4.3.0 以降、リクエストが CSRF 検証チェックに失敗した場合、デフォルトで SecurityException がスローされます。
注意
本番環境では、HTML フォームを使用する場合、ユーザーエクスペリエンスを向上させるために、このリダイレクトを有効にすることをお勧めします。
前のページにリダイレクトさせたい場合は、**app/Config/Security.php** の次の設定パラメータ値を変更します
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Security extends BaseConfig
{
// ...
public bool $redirect = true;
// ...
}
リダイレクトされると、error
フラッシュメッセージが設定され、ビューで次のコードを使用してエンドユーザーに表示できます
<?= session()->getFlashdata('error') ?>
これは、単にクラッシュするよりも優れたエクスペリエンスを提供します。
リダイレクト値が true
の場合でも、AJAX 呼び出しはリダイレクトされず、SecurityException がスローされます。
CSRF 保護の有効化
**app/Config/Filters.php** を変更し、csrf フィルターをグローバルに有効にすることで、CSRF 保護を有効にできます
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
public $globals = [
'before' => [
// 'honeypot',
'csrf',
],
];
// ...
}
選択した URI を CSRF 保護からホワイトリストに登録できます(たとえば、外部から POST されたコンテンツを期待する API エンドポイント)。これらの URI は、フィルターに例外として追加することで追加できます
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
public $globals = [
'before' => [
'csrf' => ['except' => ['api/record/save']],
],
];
// ...
}
正規表現もサポートされています(大文字と小文字は区別されません)
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
public $globals = [
'before' => [
'csrf' => ['except' => ['api/record/[0-9]+']],
],
];
// ...
}
特定のメソッドに対してのみ CSRF フィルターを有効にすることもできます
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Filters extends BaseConfig
{
public $methods = [
'get' => ['csrf'],
'post' => ['csrf'],
];
// ...
}
警告
$methods
フィルターを使用する場合は、自動ルーティング(レガシー)を無効にする必要があります。 自動ルーティング(レガシー) は、任意の HTTP メソッドがコントローラーにアクセスすることを許可するためです。予期しないメソッドでコントローラーにアクセスすると、フィルターがバイパスされる可能性があります。
HTML フォーム
フォームヘルパーを使用する場合、form_open()
は自動的にフォームに非表示の csrf フィールドを挿入します。
注意
CSRF フィールドの自動生成を使用するには、フォームページで CSRF フィルターをオンにする必要があります。ほとんどの場合、GET
メソッドを使用してリクエストされます。
そうでない場合は、常に使用可能な csrf_token()
および csrf_hash()
関数を使用できます
<input type="hidden" name="<?= csrf_token() ?>" value="<?= csrf_hash() ?>" />
さらに、csrf_field()
メソッドを使用して、この非表示の入力フィールドを生成できます
// Generates: <input type="hidden" name="{csrf_token}" value="{csrf_hash}" />
<?= csrf_field() ?>
JSON リクエストを送信する場合、CSRF トークンをパラメータの 1 つとして渡すこともできます。CSRF トークンを渡す次の方法は、csrf_header()
関数で名前が利用可能な特別な HTTP ヘッダーです。
さらに、csrf_meta()
メソッドを使用して、この便利なメタタグを生成できます
// Generates: <meta name="{csrf_header}" content="{csrf_hash}" />
<?= csrf_meta() ?>
ユーザーが送信するトークンの順序
CSRF トークンの可用性チェックの順序は次のとおりです
$_POST
配列HTTP ヘッダー
php://input
(JSON リクエスト) - JSON をデコードしてから再エンコードする必要があるため、このアプローチは最も遅いことに注意してください。php://input
(生のボディ) - PUT、PATCH、および DELETE タイプのリクエストの場合
注意
php://input
(生のボディ) は v4.4.2 以降でチェックされます。
その他の役立つメソッド
Security クラスのほとんどのメソッドを直接使用する必要はありません。CSRF 保護に関連しない、役立つと思われるメソッドを以下に示します。
sanitizeFilename()
ディレクトリトラバーサル攻撃やその他のセキュリティ上の脅威を防ぐために、ファイル名をサニタイズしようとします。これは、特にユーザー入力によって提供されたファイルに役立ちます。最初のパラメータはサニタイズするパスです。
ユーザー入力が相対パス(例:file/in/some/approved/folder.txt)を含むことが許容される場合は、2 番目のオプションパラメータ $relativePath
を true
に設定できます。
<?php
$path = $security->sanitizeFilename($request->getVar('filepath'));