در حال بارگذاری ...

Key Rotation Problem0:00

You probably already know that the app key in your .env file is used by Laravel to encrypt or decrypt values. That could be, for example, the session cookie that's being used to ensure you're the same person across web requests. But in the case of our User model, I also use it to encrypt this government ID in the database so that we're not storing it in plain text. You can see on the front end that because of that encryption, we're able to decrypt this value and display it to the user. One common security practice is to rotate your encryption keys every so often, which you can do with php artisan key:generate. The issue is, on the front end, when your user makes a new request, they'll be logged out. Not only is that strange, but when they log in, in this case, they're going to receive an exception. Why? Because the encryption

Using Previous Keys0:48

user makes a new request, they'll be logged out. Not only is that strange, but when they log in, in this case, they're going to receive an exception. Why? Because the encryption key has changed, meaning that their government ID can no longer be decrypted from the database, causing a huge problem. Laravel 11 attempts to make this process less painful by allowing you to define any previous keys before rotating encryption keys. So here's the original key used. Now if we go back to the application and refresh, note that the exception disappears. Essentially, Laravel is going to attempt to decrypt using your standard app key, but if that fails, well, it will loop through any previous keys you've defined and it will decrypt with those instead until it finds a matching result.

Migrating Custom Encrypted Data1:28

that fails, well, it will loop through any previous keys you've defined and it will decrypt with those instead until it finds a matching result. Now the cool thing is, at least for your session cookies, it will re-encrypt using the new key. In other words, as your users log in, they will all naturally be updated to the latest application key. That isn't the case with any custom encryption data, such as our government ID. So for our example, if we were to remove this encryption key and then refresh, yeah, we're going to get that exception again. There are different approaches for fixing this. I'll show you just one. Let's start in the terminal by creating a new job. php artisan make:job. We'll call it MigrateGovernment

Building Migration Job2:05

There are different approaches for fixing this. I'll show you just one. Let's start in the terminal by creating a new job. php artisan make:job. We'll call it MigrateGovernmentIDs. We need to make sure that this is a batchable job, so let's add that trait. And in the constructor, we'll accept a public read-only integer, which we'll call lastID, and it can have a default value of zero. All right, let's come down to the handle method here. The first thing we need to do is chunk up our users. I'm going to grab one page using a special method on Eloquent, users equals User::forPage(afterId). We can choose how many items per page with the first parameter, let's say 100. And then the second parameter will be the lastID that we pass into the job.

let's say 100. And then the second parameter will be the last ID that we pass into the job. Then we can call get to actually grab the results. Let's use users each to loop over each user like so. And then inside disclosure, we want to reset the governmentID so that it decrypts and then re-encrypts the value. That's as simple as saying user->governmentID equals user->governmentID and Laravel will do the rest. Let's save that back to the database. And when saved, well, we need to check if there are any more users to be processed. So we could say something like if users is not empty, then what we actually want to do is grab this batch and we want to add to the batch with a new instance of this job, passing in the last users ID. So users last, and we're looking for the identifier.

Creating Key Rotate Command3:29

is grab this batch and we want to add to the batch with a new instance of this job, passing in the last User's ID. So users last, and we're looking for the identifier. Very good. So let's just run through this code again. We construct a new instance of the job with the last ID. We handle that job by grabbing a page of users. Each user will decrypt and re-encrypt the government ID using those keys that we define in our .env file. We save it back to the database. We check if there are any more users to process basically by saying, well, did this actually return a result? And if there are more users to process, we'll release a new job onto the queue so that the process can start again. To set this going, why don't we go to console.php and let's create a very simple artisan command. Perhaps we could call this keyRotate. All right. So in here, we'll simply call the key

going, why don't we go to console.php and let's create a very simple artisan command. Perhaps we could call this keyRotate. All right. So in here, we'll simply call the keyGenerate function, this call keyGenerate, like so. And then we want to create a batch, which is bus. So bus batch, we're going to add an instance of the MigrateGovernmentIDs. So new MigrateGovernmentIDs, and then we'll call dispatch on that job. Everything else should just happen. So let's jump into .env. We'll take our existing encryption key. We'll add it to our app.previousKeys. Then we're going to come to the terminal and we'll run our command, php artisan key rotate. And once the command has been executed, we can run our queue. Of course, on your server, this would already be running and you can see how this is batching up into separate jobs until all of our users have been migrated.

Running Migration and Cleanup5:08

run our queue. Of course, on your server, this would already be running and you can see how this is batching up into separate jobs until all of our users have been migrated across. Hopefully now, if we come back and remove all of these previous keys, and then we jump into our browser and refresh, log in, note that this has been migrated forwards. Let's do the process one more time. So I take my existing application key, we'll create app previous keys, and I'll drop that original one in. When it comes time to rotate my keys, I can use my brand new command that I've created, php artisan key:rotate. We can see that the application key has now changed, but we already have our previous key in place to allow Laravel to decrypt old values, which should mean that when we reload in the browser, we're not logged out, which is the case. That's wonderful. Now we can also run our queue again.

to allow Laravel to decrypt old values, which should mean that when we reload in the browser, we're not logged out, which is the case. That's wonderful. Now we can also run our queue again. That's going to process all of our users in the database. And once that's finished, well, we can confidently come into .env and remove the APP_KEY, refresh, and everything continues to work. Keep in mind that whilst this works for my government ID, your code might be different. It might have different edge cases and scenarios you need to handle. So think about those edge cases as you migrate your data across. Also, remember, you don't have to delete your old keys. At some point, you probably do want to get rid of them, but there's no time limit on how long you can keep them. So keep them for as long as makes sense to ensure that your users have the best possible experience and aren't going to

there's no time limit on how long you can keep them. So keep them for as long as makes sense to ensure that your users have the best possible experience and aren't going to receive errors, exceptions, bugs, problems caused by rotating application keys. I imagine over time, Laravel is going to introduce more tools to make migrating data like this simpler, but it's already such a great improvement to be able to define your previous keys in .env so that encryption and decryption doesn't break entirely anytime you rotate your encryption keys.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟