1
2
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

【Laravel】メソッドインジェクションを利用してCookieの値を偽装する

Last updated at Posted at 2024-07-17

引き続きLaravel v8 を使っています。化石を使っています。

前回の続きです。

今回紹介するユースケースとしては、

テストしたいCookie処理を含むサービス存在しており、そのメソッド使用しているcontrollerのURLを呼ぶと色々副作用がありそうで面倒くさそうなので、そのメソッド単体を呼び出せるようにしてテストしたい

というケースです。

Cookie関連の処理を含むメソッドは、Cookieの特性上、URLリクエストを通してテストする必要があります。

この方法で取得されるCookieは暗号化されているので、暗号化処理のミドルウェアを無効にします。use で WithoutMiddleware をインポートすると他のミドルウェアも無効になってしまうので、以下の記述を対象のテストケースの先頭に書きます。

$this->WithoutMiddleware(\App\Http\Middleware\EncryptCookies::class);

テストしたいメソッドは以下です。Cookie::queue() メソッドが含まれている処理です。

ArticleService.php(とします)
public static function refresh_cookie () {
    $cookie = Cookie::get("cookie1");
    if ($cookie) {
        return $cookie;
    }

    $cookieList = ['A', 'B', 'C'];
    $newCookie = $cookieList[array_rand($cookieList)]; 
    Cookie::queue("test", $newCookie, '30');
    return $newCookie;
}

次に、対象メソッドを呼び出すテスト用のパスを作っちゃいましょう。

routes/web.php

Route::get('/test-cookie', function () {
    $newCookie = ArticleService::refresh_cookie();
    $cookie = cookie('cookie1', $newCookie, 60);
    return response('Cookie has been set')->cookie($cookie);
});

Cookie::queue() は、リクエストの終了後にクッキーを設定する非同期関数なので、リクエストを走らせてレスポンスを取得する必要があります。

そのために、テストリクエスト用のパスを作る必要があるということですね。そしてレスポンスにメソッドで取得したクッキーをセットする必要もあります。

こうして環境構築をして、出来上がったテストコードは以下のようになります。

public function test_refresh_cookie__クッキーが設定されているか(): void
{
    // Cookieの暗号化を無効にする
    $this->WithoutMiddleware(\App\Http\Middleware\EncryptCookies::class);
    
    $cookies = ['cookie1' => null];
    $response = $this->call('GET', '/test-aaa', $cookies);

    $cookie = $response->headers->getCookies()[0];
    $this->assertContains($cookie->getValue(), ["A", "B", "C"]);
    # -> OK
}

ところで、公式のCookie偽装方法は、withCookie , withCookies を使用してGETリクエストを送信しています。 

$response = $this->withCookie('cookie1', 'A')->get('/');

しかしこのメソッドではミドルウェアを無効にしても暗号化がされたものが取得されます。
なので以下をミドルウェアの無効化の記述の下に挿入します。

$this->WithoutMiddleware(\App\Http\Middleware\EncryptCookies::class);
$this->disableCookieEncryption();

この場合の完成系は以下になります。

public function test_refresh_cookie__クッキーが設定されているか(): void
{
    // Cookieの暗号化を無効にする 
    $this->WithoutMiddleware(\App\Http\Middleware\EncryptCookies::class);
    $this->disableCookieEncryption();

    $cookies = ['cookie1' => null];
    $response = $this->withCookies($cookies)->get('/test-cookie');

    $cookie = $response->headers->getCookies()[0];
    $this->assertContains($cookie->getValue(), ["A", "B", "C"]);
    # -> OK
}

Cookieをランダムに返しているため、assertionassertContains を利用していますが、取得できるCookieが自明の場合なら、assertCookieassertPlainCookie でアサーションしましょう。

こうしてCookieの処理を持つ関数を他に影響を及ぼすことなく/考慮することなく、テストが出来ます。

1
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
1
2