Laravel Encrypting Model Data: You are doing it wrong!

Luciano Bargmann
May 25 · Unlisted

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:

<?php

Usage:

class Account extends Model