These days security online is kind of a big deal. Major hacking stories are becoming a monthly event. The recent Ashely Madison hack is an example of security failures on a lot of different levels. Now its difficult to know for sure since there are rumours that it was an inside job. And Inside jobs are kind of hard to protect against. But that doesn’t mean you can’t improve security.

People talk a lot about storing passwords as plain text in the database as being a big no no. And it is for sure. But what about the other data? Emails. Phone numbers. Other personal info.

I am currently working on a medical related app and in Ontario, there are pretty strict regulations regarding how you store medical information online. I had been struggling with this for a few days. Then as usual, Laravel presented the solution. Using a Trait to encrypt fields on I/O. So here is how to do it.

First lets create the Trait itself. The Trait sort of intercepts reading from and writing to the database. It looks to see whether you have asked that a certain parameter to be encrypted, and if so Encrypts it on the way in and Decrypts it on the way out. I store Traits in app/Traits but you can store them wherever you want as long as you namespace it accordingly.

app/Traits/EncryptableTrait.php


namespace App\Traits;

use Illuminate\Support\Facades\Crypt;

trait EncryptableTrait {

    public function getAttribute($key)
    {
        $value = parent::getAttribute($key);

        if (in_array($key, $this->encryptable) && ( ! is_null($value)))
        {
            $value = Crypt::decrypt($value);
        }

        return $value;
    }

    public function setAttribute($key, $value)
    {
        if (in_array($key, $this->encryptable))
        {
            $value = Crypt::encrypt($value);
        }

        return parent::setAttribute($key, $value);
    }
} 

So in the above example I have told my User model to use the EncryptableTrait on the name, phone and email fields. Now when I create or save a user, the fields are encrypted using the built-in Crypt package. And thats it!

Here is the user data table unencrypted:
users_unencrypted

 

And here is the data encrypted

Screen Shot 2015-08-26 at 4.15.53 PM

 

Which one would you rather your hacker have access to? But what is really going on here?

Your app key and whats happening behind the scenes

I am not even going to dive all the way in to how the Crypt feature in Laravel works. But I will tell you a major part of the encrypting process is made possible using the random key that Laravel generates. You will find this in your .env file under APP_KEY. So it is pretty important to keep this key safe and away from evil.

But there is something else. If you lose this key, and for some reason your application explodes and you can no longer recover it, you will not be able to decrypt your data. The key is required to read any data that was encrypted with said key. Thats why you may notice that if you regenerate the key, your passwords on the app will no longer work. This is because when the user registered the password was encrypted with the then current app key.

So this means if you have an application where the main data must be encrypted, you need to have an organized was of managing the app key, and a process for changing the key if necessary. This may involve keeping the key backed up offline somewhere. It will also require a process for changing the key. Remember if you simply change your app key, none of the data will be readable and everything will break. So the process of changing a key if necessary might be to write a script that can decrypt the entire database against the old key, generate a new key, then re-encrypt the entire database with the new key.

Its a bit scary I know. If anyone has experience with this by all means chime in below.


  • Peter Lounton

    Thank for the post it is exactly what I needed, it works well and the field are now being encrypted. Might seem a silly question but how do you, while using the Laravel 5 built-in Auth, decrypt for a user to log-in…

    Thanks

  • Sorry I missed this. Can you explain the issue? Are encrypting the user’s email address?

  • Nimzy Kevin Maina

    Hi, this is a wonderful post. I need help with this. The decrypt is not working automatically for a collection of objects, I have to manually dycrypt the values from the database so that I can access them. Its working for one item but not for a collection of items. I’m using laravel 5.2

  • The decryption only happens when you access the model attribute via $model->column name or through eloquent. Are you trying to pull the element directly?

  • Gökhan Efendi

    For instance, you have 20 users which their names start with S letter. When you search encyrpted values it will return 0.

    Users::where(‘name’, ‘LIKE’, ‘S%’)->get()

    How can I fix this issue?

  • Gökhan Efendi

    Also you have to check every create/update action with laravel validator. Because encyrpted values could be same like phone or email but decyripted values always unique.

  • I don’t have a solution to that. Unfortunately encrypted data is hard to search. I have found a better solution in general is to do database level encryption using postgres pgcrypto for example. There are also options for mySql where you can have the database automatically encrypted at rest.

  • Celia Kessassi

    hi there, I am asking the same question I have encrypted the user’s email , now authentification doesn’t work

  • You cannot encrypt the users email and use the built in authentication. You would need to have a custom login method. Here is a similar discussion. http://laravel.io/forum/02-20-2014-search-encrypted-data

  • Celia Kessassi

    thx for your answer,do you recommend me to use the encrypt facade on the email or is there eny other way to protect the email and still use the laravel build-in authentification ?

  • James Jordan Winstanley

    The problem with this, is that is an attacker has a sqlshell to your database, then they also have the privileges of the www-data user, which has to have read access to the .env file. Basically, if they get access to your database, they will still have the full means to decrypt it available.

  • Pablo Gil Pereira

    Do you have a solution now?