Laravel: Encrypt Models Data with Casts

Tutorial last revisioned on March 17, 2024 with Laravel 11

If you want to avoid storing sensitive DB data (like passport numbers) as plain text, Laravel can encrypt it in Eloquent Models by simply casting it as encrypted. Let's see how it works.

It looks something like this:

We don't want our user passport numbers stored in plain text in our database, so encryption is a great way to protect it. This can encrypt any data in your models, not just user data.


Database Setup

Our database does not need anything special here. You must ensure that the column you want to encrypt is a string/text column (based on the data amount), even if the original value contains only numbers, like passport numbers in our case.


Model Setup

In our model, we need to add the protected $casts property and the column we want to encrypt. In our case, it is passport_number:

// ...
 
protected function casts(): array
{
return [
'passport_number' => 'encrypted',
];
}
 
// ...

That's it! Now, whenever you save the passport number on your user model - it will be encrypted, and on retrieval, it will get decrypted. How cool is that?


IMPORTANT WARNING: Protect Your App Key

The encryption algorithm mentioned above is based on your application's APP_KEY value. In your .env file, you should have something like this:

APP_KEY=base64:QikAJAlo0evYLq2RYFxGv/PRrSIfJcNDj2qiFRp1oUs=

When talking about encryption, you must keep your APP_KEY safe. If someone gets access to it - they can decrypt all your encrypted data. So please keep it safe and don't share it with anyone.


What Happens If You Change Your App Key?

Your APP_KEY is re-generated whenever you run php artisan key:generate. But what happens to your encrypted data if you change your APP_KEY?

The encrypted data is lost

That's right. If you change your APP_KEY - all your encrypted data will be lost. This is because this key is used for the encryption/decryption, and changing it - messes up the decryption process. Just look at this example:

And if we change the key:

So the main idea is this: DO NOT RUN key:generate ON PRODUCTION SERVER.

Be careful with your APP_KEY and don't lose it. It's a good idea to keep a backup of it somewhere safe.

avatar

I have a belief that when attacker got access to the data stored in DB, it DOES mean that it has an access to the file system as well. Thus, in my opinion, encrypting data stored in DB is not the all-in-one solution. Better stick to improving overall security of your application, like preventing data leaks via sql injections, remote code execution, check your file permissions as well

avatar

There is couple of things to unravel here, so let's do it:

  1. If the attacker gets access to DB - it doesn't always mean it has access to files. Your DB can be hosted in a separate server away from the files. This renders the data useless.
  2. This example is not meant to be a one-size-fits-all solution for all security things. This is a requirement in order to be compliant with some systems. For example, your database should never have someones social identification number (passport number and so on) completely free and visible to everyone. It has to be shown in a specific place, but the developer or data analyst has no need to see it. This solves it.

Overall, you are right on the part that you need to improve overall security of the application. But this was not targeted at that. This was targeted at compliance and hiding the data in the database. That's all it does.

avatar

Yeah, you are right. However, I meant a standard Laravel application where both DB & files stored on the same server, usually on a shared hosting server. In the best case scenario, it is correct - DB on the remote server makes encrypted data useless for an attacker unless he has a key AND this key is stored securely.

Never thought about this package from the GDPR-alike compliance side, though 🤔

avatar

Well, this is where our standards differ I would say. For me a standard setup is:

VPS server with files + db -> insensitive data

VPS server with files + separate VPS server for database -> sensitive data

As for shared servers... I never recommend them to anyone and they should be left in the past IMHO :)

avatar

these do not differ. I am just taking into account most publicly available Laravel apps, but my course of action for any my Laravel peoject would be the same as your :)

Like our articles?

Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1057 lessons, total 42 h 44 min)
  • 79 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials