Created
January 26, 2020 16:24
-
-
Save themsaid/ef376d7642be69c1110a0a49b0beb0ea to your computer and use it in GitHub Desktop.
Re-encryption after APP_KEY rotation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Providers; | |
use App\Encrypter; | |
use Illuminate\Support\Str; | |
use Illuminate\Support\ServiceProvider; | |
class AppServiceProvider extends ServiceProvider | |
{ | |
/** | |
* Register any application services. | |
* | |
* @return void | |
*/ | |
public function register() | |
{ | |
$this->app->singleton('encrypter', function($app){ | |
$config = $app->make('config')->get('app'); | |
if (Str::startsWith($key = $config['key'], 'base64:')) { | |
$key = base64_decode(substr($key, 7)); | |
} | |
return new Encrypter($key, $config['cipher']); | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App; | |
use Illuminate\Support\Str; | |
class Encrypter extends \Illuminate\Encryption\Encrypter | |
{ | |
/** | |
* Decrypt the given value. | |
* | |
* @param string $payload | |
* @param bool $unserialize | |
* @return mixed | |
* | |
* @throws \Illuminate\Contracts\Encryption\DecryptException | |
*/ | |
public function decrypt($payload, $unserialize = true) | |
{ | |
try{ | |
return parent::decrypt($payload, $unserialize); | |
}catch(\Throwable $e){ | |
$currentKey = $this->key; | |
$this->key = Str::startsWith(config('app.old_key'), 'base64:') | |
? base64_decode(substr(config('app.old_key'), 7)) | |
: config('app.old_key'); | |
return tap(parent::decrypt($payload, $unserialize), function () use ($currentKey) { | |
$this->key = $currentKey; | |
}); | |
} | |
} | |
} |
@themsaid I know this is a pretty old example, but still the only semi-official response on rotating keys by the Laravel maintainers. I just got bitten by the tap
call - if the second decryption attempt fails, the callback never runs, and the key will not be reset.
This is usually no problem, but in Octane applications, the Encrypter instance stays alive after the request is complete. An easy fix would be to use try-finally instead:
try {
return parent::decrypt($payload, $unserialize);
} finally {
$this->key = $currentKey;
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
thanks you for this 👍