PHP
laravel
cookie
セキュリティ
laravel5.5

同一ドメインにLaravel5.5.43と、それ以前の5.*系を配置する時は気をつけようというお話

同一ドメイン上に複数のLaravelのサーバが立ってるっていうのもおかしな話ではあるんですが、まぁ。
とあるパスは5.5.43で処理させて、他のパスは5.*で処理をさせるとか、そういう場合でしょうか:relieved:

5.5と5.*でcookieを共有すると爆発する:head_bandage:

同一ドメインだからといって、APP_KEYの値を同じにしてcookieをそのまま共有しようとすると爆発を起こします。
5.5とそれより前のページを行ったり来たりしていると、なんだかエラーが出てきてしまいます。

cookieの値がserialize/deserializeできないというエラー:alien:

タイトルのようなエラーが出てきてしまいます。
何故かと言うと、laravel5.5.43から、参照しているilluminate/cookieに変更が入っているのです。

5.5のソース:five:

5.5/Middleware/EncryptCookies.php

    /**
     * Indicates if cookies should be serialized.
     *
     * @var bool
     */
    protected static $serialize = false;

   /**
     * Decrypt the given cookie and return the value.
     *
     * @param  string  $name
     * @param  string|array  $cookie
     * @return string|array
     */
    protected function decryptCookie($name, $cookie)
    {
        return is_array($cookie)
                        ? $this->decryptArray($cookie)
                        : $this->encrypter->decrypt($cookie, static::serialized($name));
    }

5.4のソース:four:

5.4/Middleware/EncryptCookies.php

   /**
     * Decrypt the given cookie and return the value.
     *
     * @param  string|array  $cookie
     * @return string|array
     */
    protected function decryptCookie($cookie)
    {
        return is_array($cookie)
                        ? $this->decryptArray($cookie)
                        : $this->encrypter->decrypt($cookie);
    }

serializedとは何者:spy:

一言で言うとcookieをserializedする、しないを管理するというフラグです。
5.5では生の値で保存しているのに、それより前ではserializeしているため、deserializeでエラーになったり、途中で値が消えたりとカオスな挙動になったりします。

対策:robot:

動かしたいだけなら、5.5側のミドルウェアのEncryptCookiesのクラスにserialized = trueの設定をしてあげればOKです。

/**
 * Indicates if cookies should be serialized.
 *
 * @var bool
 */
protected static $serialize = true;

ただ、後述の理由を踏まえるとやらない方がいいかもしれないです。

なぜserializedされなくなったのか?:thinking:

https://laravel.com/docs/5.6/upgrade#upgrade-5.6.30

ここに書いてありました!
5.5とそれ以前……ではなく、5.6.30へのリリースから、この修正が適用されたようです。(5.5の最新版にも適用されています)

内容としては

Laravel 5.6.30 disables all serialization / unserialization of cookie values. Since all Laravel cookies are encrypted and signed, cookie values are typically considered safe from client tampering. However, if your application's encryption key is in the hands of a malicious party, that party could craft cookie values using the encryption key and exploit vulnerabilities inherent to PHP object serialization / unserialization, such as calling arbitrary class methods within your application.

ほうほう、なるほど:tired_face:

つまり、5.6.30からcookieのserialize、unserializeを辞めました。
全てのLaravelのcookieは暗号化されてるからクライアントから弄くられて改ざんされても安全だよ!
だけど、悪意のあるユーザにAPP_KEYの値が手に入っちゃうと、serialize、deserializeするところで、悪意のあるコードを実行されてしまう!

超意訳ですが。

APP_KEYの値が漏れている時点で大変なことになりそうな気もしますが:skull:
こういった問題もあったので、過去との互換性を切り捨ててでもセキュリティアップデートをしたようです。

とはいえ、APP_KEYを必要最低限の人にしか見せないことが一番の対策ですね……

最後に

株式会社ネコカリでは猫の手も借りたい🔥炎上中🔥なお仕事を募集しています!
一緒に働くメンバーも募集していますので、よかったら是非!