Laravel Encrypting Model Data: You are doing it wrong!

Luciano Bargmann

TL;DR: Use bootable model traits to ensure you are encrypting/decrypting your data when saving/loading your data.

If an attacker gets access to your database, he can read or change important data such as a credit card number, or an account virtual balance. To mitigate damage in a disaster-scenario like that, you can encrypt your data.

Quick search on Google and I found this forum post with exactly what I need! Use a trait on your model and boom! Magic happens.

Code from Laracasts forum

Wrote my unit tests, and on first test run, blood and tears as most of my tests failed. Checking the error, Oh Sh*t… of course! I was encrypting an integer, and it became a loooong string after encryption. Ok, change the field types to text in the migration files and now it all works fine. All tests pass: I am creating users, checking the database… data is encrypted! Reading them back… nice, I have my precious integers once more. All good and marvelous with no more than 20 lines. Thanks Laravel!

A few days go by and I wrote a function to load all records in a certain model:

$data = Model::all()->toArray();

But the values for my encrypted fields were still… encrypted. WTF? It turns out that loading an Eloquent Model and converting the items into an array (or JSON) does not use the getAttribute($key) function from the model.

And this is where the example from Laracasts forum is flawed. You must use a Bootable Model Trait and listen for saving and retrieved events. Here is my Encrypted trait (picture for better readability, see the code block at the end of the article):

The CORRECT way for Encrypting Model Data

And as promised, the complete code for your copy & paste pleasure:

Trait:

<?phpnamespace App\Traits;use Illuminate\Support\Facades\Crypt;trait Encryptable{  public static function bootEncryptable()  {    static::retrieved(function ($model) {      foreach ($model->encryptable as $key) {        $value = $model->getAttribute($key);        $model[$key] = Crypt::decrypt($value);      }    });    static::saving(function ($model) {      foreach ($model->encryptable as $key) {        $value = $model->getAttribute($key);        $model[$key] = Crypt::encrypt($value);      }    });  }}

Usage:

class Account extends Model{  use Encryptable;
/**
* The attributes that should be encrypted on save. * * @var array */ protected $encryptable = [ 'balance', 'security_level' ];}

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade