Laravelで最悪クビが飛ぶコードの書き方


ここはtoCなWebサービスを展開するIT企業。物語はここから始まる

先輩「後輩くん、検証環境だけで動かしたいライブラリがあるんやけど入れてくれる?」

後輩「わかりました。」

・・・数分後

後輩「こんなコードでええやろ。これなら検証環境でのみライブラリが有効化されるハズや」

if (env('APP_ENV') != 'production') {
  // 検証環境でのみ動作させたいコード
}

後輩「よし。検証環境でちゃんと動いとるな。本番にもデプロイや、ぽちー」

・・・数分後

先輩「大変や後輩君!本番環境で表示されてはいけない情報が表示されてしまってるわ!セキュリティインシデントや!」

どうしてこうなってしまったのでしょうか、原因を見ていきましょう。

何が起こったのか?

後輩くんが追加したのは以下のコードです。

if (env('APP_ENV') != 'production') {
  // 検証環境でのみ動作させたいコード
}

if文で検証環境かどうかを調べて、検証環境の場合のみライブラリを有効化する様なコードを書いたにも関わらず
本番環境でもライブラリが有効化されてしまいました。

どうしてこうなるのか?

env()には以下の仕様があります。

php artisan cache:configを実行するとenv()nullを返すようになります。

by 公式ドキュメント

今回のケースでは、本番環境ではコンフィグをキャッシュする運用になっており、デプロイすると自動的にphp artisan cache:configが実行される様になっていました。

その結果、以下のコードは本番環境でもtrueになってしまい、意図せず、検証環境用のコードが本番環境で実行されてしまいました。

env('APP_ENV') != 'production'

もし、Debugbarを有効化する様なコードがここにかかれていた場合、本番環境でDebugbarが有効化されてしまいます。
するとDBアクセス情報などが利用者の画面に表示されてしまうので簡単に情報漏洩が発生します。

じゃあどうすればいいの?

config('app.env')を使いましょう。
書き直すと以下の様になります。

if (config('app.env') != 'production') {
  // 検証環境でのみ動作させたいコード
}

上記であればphp artisan cache:configをしても問題なく動作します。

(そもそも環境で分岐する様なコードを避けるというのも大正解だと思います)

ちなみに公式ドキュメントではApp::environment()の使用を推奨している様です。
こちらも内部的にはconfigの'app.env'を参照しています。

$app->detectEnvironment(function () use ($config) {
    return $config->get('app.env', 'production');
});

以上です。
「コンフィグをキャッシュするとenv()がnullを返すようになる」仕様を知らなくてハマった人いっぱいいそうだなぁと思って書きました。
誰かが救われると幸いです。