3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

CakePHP「3.0」で「CSRF」対策済みのアクション「テスト」を行う

Last updated at Posted at 2019-11-28

CakePHP「3.0」で「CSRF」のコントローラー「テスト」を行う

こんにちはNonです。
今回はあるプロダクトの開発に出くわしたちょっとした内容の課題を解決する手法についてお話しようと思います。
かなりニッチな需要となりますので、お役に立てるかわかりませんが参考になれば嬉しいです。

はじめに

環境は

  • CakePHP「3.0」

です。CakePHP「3.1」以降ではCSRF対策のテスト手法は確率されているので、この記事の対象者はCakePHP3.0のユーザーということになります。

結論

CakePHP3.0では

/**
 * Test sample method
 */
public function testSample()
{
    // sample-tokenの部分は任意の値で大丈夫です。
    $this->cookie('csrfToken', 'sample-token');
    $url = Router::url(['controller' => 'Sample', 'action' => 'sample']);
    $data = [
        'sample' => 'サンプル',
        '_csrfToken' => 'sample-token'
    ];
    $this->post($url, $data);
}

sample-tokenの部分は任意の値で大丈夫です。

CakePHP3.1以降では

/**
 * Test sample method
 */
public function testSample()
{
    $this->enableCsrfToken();
    $this->enableSecurityToken();
    $url = Router::url(['controller' => 'Sample', 'action' => 'sample']);
    $data = [
        'sample' => 'サンプル',
    ];
    $this->post($url, $data);
}

事例

とあるプロダクトの開発中、こんな出来事に遭遇しました。

あれ?このプロダクトCSRF対策されてないやん……

このプロダクトは簡素なもので、最近引き継いだばかり、プロトタイプと言っていいほどの機能にしか持っていないので、当時の作成者は面倒臭くてCSRF対策を忘れていたのでしょう。

よっしゃ、CakePHP3だしCSRF対策楽勝やろ!やったろ!

軽い気持ちで実装しました。

問題

CSRF対策は導入できたけどPHPUnit通らなくなってもうた……

CakePHP3の更新HPCSRFアクションのテストの項目では……

CsrfComponent や SecurityComponent で保護されたアクションのテスト
SecurityComponent または CsrfComponent のいずれかで保護されたアクションをテストする場合、 テストがトークンのミスマッチで失敗しないように自動トークン生成を有効にすることができます。

public function testAdd()
{
    $this->enableCsrfToken();
    $this->enableSecurityToken();
    $this->post('/posts/add', ['title' => 'Exciting news!']);
}

また、トークンを使用するテストで debug を有効にすることは重要です。SecurityComponent が 「デバッグ用トークンがデバッグ以外の環境で使われている」と考えてしまうのを防ぐためです。 requireSecure() のような他のメソッドでテストした時は、適切な環境変数をセットするために configRequest() を利用できます。

// SSL 接続を装います。
$this->configRequest([
    'environment' => ['HTTPS' => 'on']
]);

バージョン 3.1.2 で追加: enableCsrfToken() と enableSecurityToken() メソッドは 3.1.2 で追加されました。

あれ?

スクリーンショット 2019-11-28 10.35.19.png

あかんやん
そら通らんわ。Cakeのソース追ってもenableCsrfToken()enableSecurityToken()も通りで無いわけや……

解決

でもよく考えて見ると、CSRFってトークン送信してそのトークンが合ってるだけで良い訳で、しかもPHPUnitでのリクエストが送信されれば良い(CSRF対策のテストがしたいわけではない)ので、普通にトークン送信すれば良いんじゃない?

ということで、やってみました。

CakePHP3の仕様では、HTML側に埋め込まれるCSRFトークンは

<input type="hidden" name="_csrfToken" value="43b804c28f3bd305a513c7c8ba1f1ce61e5ac6a9">

こんな感じなので、PHPUnitでリクエストするときは

$this->post($url, [
    '_csrfToken' => '43b804c28f3bd305a513c7c8ba1f1ce61e5ac6a9',
])

という形式になっていれば、OK。

この送信したトークンをサーバー側のクッキーと比較するはずなので、同様にPHPUnitでは

$this->_cookie('csrfToken', '43b804c28f3bd305a513c7c8ba1f1ce61e5ac6a9');

命名はクライアントの情報になってしまいますが、ここで確認しました。

スクリーンショット 2019-11-28 10.47.04.png

ということで最終的に下記のようなテストコードに。

/**
 * Test sample method
 */
public function testSample()
{
    // sample-tokenの部分は任意の値で大丈夫です。
    $this->cookie('csrfToken', 'sample-token');
    $url = Router::url(['controller' => 'Sample', 'action' => 'sample']);
    $data = [
        'sample' => 'サンプル',
        '_csrfToken' => 'sample-token'
    ];
    $this->post($url, $data);
}

結果

無事成功しました。

余談

スクリーンショット 2019-11-28 10.35.19.png

CakePHP3.1.2以降では……

/**
 * Test sample method
 */
public function testSample()
{
    $this->enableCsrfToken();
    $this->enableSecurityToken();
    $url = Router::url(['controller' => 'Sample', 'action' => 'sample']);
    $data = [
        'sample' => 'サンプル',
    ];
    $this->post($url, $data);
}

これでOKです。

設定するの面倒なので、CakePHPのバージョンあげますか……

最後に

フレームワーク独特の課題にぶつかりまして、少し楽しかったです。
実はもうCakePHP3のバージョンアップソースは完成しているので、またテスト内容をリライトしなければならないのですが、CakePHP3.0特有の課題を見つけることができてよかったと思います。

地味な内容になってしまいましたが、今後もニッチな内容のものを見つけましたら記事にしていこうと思います。

その時はよしなに。

.

おまけ

https://labo.nozomi.bike
僕の個人ブログです。(Laravel + Vue)で自作。
こっちにしかない記事も多数ありますので、よかったら見てやってください。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?