セキュリティ

セキュリティクラスには、クロスサイトリクエストフォージェリ(CSRF)攻撃からサイトを保護するのに役立つメソッドが含まれています。

ライブラリの読み込み

ライブラリを読み込む唯一の目的が CSRF 保護を処理することである場合、ライブラリを手動で読み込む必要はありません。ライブラリはフィルターとして実行され、手動操作は必要ありません。

直接アクセスする必要がある場合は、サービスファイルから読み込むことができます

<?php

$security = \Config\Services::security();

クロスサイトリクエストフォージェリ (CSRF)

警告

CSRF 保護は、**POST/PUT/PATCH/DELETE** リクエストに対してのみ利用可能です。他のメソッドのリクエストは保護されません。

前提条件

CodeIgniter の CSRF 保護を使用する場合でも、以下のようにコーディングする必要があります。そうしないと、CSRF 保護がバイパスされる可能性があります。

自動ルーティングが無効になっている場合

次のいずれかを実行します

  1. $routes->add() を使用せず、ルートで HTTP 動詞を使用します。

  2. 処理する前に、コントローラーメソッドでリクエストメソッドを確認します。

例:

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') を使用する必要があります。

自動ルーティングが有効になっている場合

  1. 処理する前に、コントローラーメソッドでリクエストメソッドを確認します。

例:

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 トークンの可用性チェックの順序は次のとおりです

  1. $_POST 配列

  2. HTTP ヘッダー

  3. php://input (JSON リクエスト) - JSON をデコードしてから再エンコードする必要があるため、このアプローチは最も遅いことに注意してください。

  4. php://input (生のボディ) - PUT、PATCH、および DELETE タイプのリクエストの場合

注意

php://input (生のボディ) は v4.4.2 以降でチェックされます。

その他の役立つメソッド

Security クラスのほとんどのメソッドを直接使用する必要はありません。CSRF 保護に関連しない、役立つと思われるメソッドを以下に示します。

sanitizeFilename()

ディレクトリトラバーサル攻撃やその他のセキュリティ上の脅威を防ぐために、ファイル名をサニタイズしようとします。これは、特にユーザー入力によって提供されたファイルに役立ちます。最初のパラメータはサニタイズするパスです。

ユーザー入力が相対パス(例:file/in/some/approved/folder.txt)を含むことが許容される場合は、2 番目のオプションパラメータ $relativePathtrue に設定できます。

<?php

$path = $security->sanitizeFilename($request->getVar('filepath'));