ローカル環境で不具合を再現しようとしていたときに、LaravelでThe MAC is invalid.というエラーに遭遇しました。
状況
開発環境(dev)で起きた高負荷時の不具合をローカルで再現するため、TablePlusで取得したSQLダンプをローカルDBへ適用しました。
その後に画面を開くと、次のエラーが発生しました。
Illuminate\Contracts\Encryption\DecryptException
vendor/laravel/framework/src/Illuminate/Encryption/Encrypter.php:188
The MAC is invalid.
最初に疑ったこと
The MAC is invalid.と表示されていたので、Macユーザなので恥ずかしながら最初はMacに関係するエラーなのかと思いました。
ただ、直前に別環境のDBデータをローカルへ取り込んでいたため、環境ごとに異なる設定値で暗号化されたデータを復号しようとして失敗しているのではないかと考えました。
まず、スタックトレースに出ている箇所を確認し、どの処理で復号が行われているかを追いました。
呼び出し元のコードをたどると、エラーになっていたのは暗号化済みの文字列を扱うカラムでした。ここで、SQLダンプで持ち込んだデータが原因だとほぼ判断できました。
原因
調べてみると、Laravelで暗号化した値は、暗号化したときのAPP_KEYを使って復号するみたいでした。
今回取り込んだデータは別環境のAPP_KEYで暗号化されていました。一方、ローカル環境にはローカル用のAPP_KEYが設定されています。そのため、ローカル環境では元の値を正しく復号できず、The MAC is invalid.が発生していた様子でした。
解決策
今回、他の箇所での不具合だったため、ローカルでその値を使わなかったので、
対象カラムをNULLなどに更新して、復号処理が走らない状態にしました。
値が必要な場合は、ローカル環境のAPP_KEYで暗号化し直した値を入れて、元のAPP_KEYをローカルへコピーする方法も考えられますが、今回はあくまで別の不具合調査で、解消後すぐにローカル環境を元に戻す想定だったため、そこまでは試しませんでした。
学び
ここでいうMACは、ハードウェアのMacではなく、Message Authentication Code(メッセージ認証コード)のことでした。
The MAC is invalid.は、Laravelが暗号文の整合性を確認できなかったという意味らしいです。
暗号文が壊れている場合だけでなく、今回のように別のAPP_KEYで暗号化された値を復号しようとした場合にも発生するみたいでした。
次に同じエラーを見たときは、暗号化済みの値を別環境から取り込んでいないか、APP_KEYが暗号化時と復号時で一致しているかを先に確認しようと思います。