Automatically encrypt and decrypt Laravel 5 Eloquent values

Related tags

Laravel elocryptfive
Overview

Eloquent Encryption/Decryption for Laravel 5

Build Status StyleCI Latest Stable Version Total Downloads

Automatically encrypt and decrypt Laravel 5 Eloquent values.

READ THIS FIRST

Encrypted values are usually longer than plain text values. Sometimes much longer. You may find that the column widths in your database tables need to be extended to store the encrypted values.

If you are encrypting long strings such as JSON blobs then the encrypted values may be longer than a VARCHAR field can support, and you may need to extend your column types to TEXT or LONGTEXT.

What Does This Do?

This encrypts and decrypts columns stored in database tables in Laravel applications transparently, by encrypting data as it is stored in the model attributes and decrypting data as it is recalled from the model attributes.

All data that is encrypted is prefixed with a tag (default __ELOCRYPT__:) so that encrypted data can be easily identified.

This supports columns that store either encrypted or non-encrypted data to make migration easier. Data can be read from columns correctly regardless of whether it is encrypted or not but will be automatically encrypted when it is saved back into those columns.

Requirements and Recommendations

  • Laravel 5.1 LTS (untested on 5.2 and later versions)
  • PHP > 5.6.0 (need the hash_equals() function which was added in PHP 5.6)
  • PHP openssl extension.
  • A working OpenSSL implementation on your OS. OpenSSL comes pre-built with most Linux distributions and other forms of Unix such as *BSD. There may or may not be a working OpenSSL implementation on a Windows system depending on how your LA?P stack was built. I cannot offer support for installing or using ElocryptFive on systems that do not have an OpenSSL library.

Contributors

This is Darren Taylor's Laravel 4 "elocrypt" package, ported to Laravel 5. I have made the following additions/changes:

  • Do the encryption in separate functions (encryptedAttribute and decryptedAttribute rather than inside __set and __get, and call those from setAttribute and getAttribute as that's more appropriate for Laravel 5 with the new casts features. So, for example, you can add a field to $casts and also to $encrypts so that an array can be cast to a JSON string first, and then encrypted. It should also work for Lumen.

  • Prefix all encrypted values with a tag string (default __ELOCRYPT__: ) so that plain text data can be detected and handled correctly. The task of writing a script to traverse your existing database and update all plain text data to encrypted data is left to the reader.

The original Laravel 4 package is here: https://github.com/dtisgodsson/elocrypt

Thanks to Brandon Surowiec for some extensive refactoring of the internal methods.

Installation

This package can be installed via Composer by adding the following to your composer.json file:

    "require": {
        "delatbabel/elocryptfive": "~1.0"
    }

You must then run the following command:

    composer update

Once composer update has finished, then add the service provider to the providers array in your application's config/app.php file:

    'providers' => [
        ...
        Delatbabel\Elocrypt\ElocryptServiceProvider::class,
    ],

Configuration

Publish the config file with:

    php artisan vendor:publish --provider='Delatbabel\Elocrypt\ElocryptServiceProvider'

You may then change the default prefix tag string in your .env config file:

    ELOCRYPT_PREFIX=__This_is_encrypted_data__

or alternatively you can change the default right in the config/elocrypt.php file:

    return [
        'prefix' => env('ELOCRYPT_PREFIX', '__This_is_encrypted_data__')
    ]

Usage

Simply reference the Elocrypt trait in any Eloquent Model you wish to apply encryption to and define an $encrypts array containing a list of the attributes to encrypt.

For example:

    use Delatbabel\Elocrypt\Elocrypt;

    class User extends Eloquent {

        use Elocrypt;
       
        /**
         * The attributes that should be encrypted on save.
         *
         * @var array
         */
        protected $encrypts = [
            'address_line_1', 'first_name', 'last_name', 'postcode'
        ];
    }

You can combine $casts and $encrypts to store encrypted arrays. An array will first be converted to JSON and then encrypted.

For example:

    use Delatbabel\Elocrypt\Elocrypt;

    class User extends Eloquent {

        use Elocrypt;

        protected $casts = ['extended_data' => 'array'];

        protected $encrypts = ['extended_data'];
    }

How it Works?

By including the Elocrypt trait, the setAttribute() and getAttributeFromArray() methods provided by Eloquent are overridden to include an additional step. This additional step simply checks whether the attribute being set or get is included in the $encrypts array on the model, and either encrypts/decrypts it accordingly.

Summary of Methods in Illuminate\Database\Eloquent\Model

This surveys the major methods in the Laravel Model class as of Laravel v 5.1.12 and checks to see how those models set attributes and hence how they are affected by this trait.

  • constructor -- calls fill()
  • fill() -- calls setAttribute() which has been extended to encrypt the data.
  • hydrate() -- TBD
  • create() -- calls constructor and hence fill()
  • firstOrCreate -- calls constructor
  • firstOrNew -- calls constructor
  • updateOrCreate -- calls fill()
  • update() -- calls fill()
  • toArray() -- calls attributesToArray()
  • jsonSerialize() -- calls toArray()
  • toJson() -- calls toArray()
  • attributesToArray() -- calls getArrayableAttributes().
  • getAttribute -- calls getAttributeValue()
  • getAttributeValue -- calls getAttributeFromArray()
  • getAttributeFromArray -- calls getArrayableAttributes()
  • getArrayableAttributes -- has been extended here to decrypt the data.
  • setAttribute -- has been extended here to encrypt the data.
  • getAttributes -- has been extended here to decrypt the data.

Keys and IVs

The key and encryption algorithm used are as per the Laravel Encrypter service, and defined in config/app.php as follows:

    'key' => env('APP_KEY', 'SomeRandomString'),

    'cipher' => 'AES-256-CBC',

I recommend generating a random 32 character string for the encryption key, and using AES-256-CBC as the cipher for encrypting data. If you are encrypting long data strings then AES-256-CBC-HMAC-SHA1 will be better.

The IV for encryption is randomly generated.

FAQ

Manually Encrypting Data

You can manually encrypt or decrypt data using the encryptedAttribute() and decryptedAttribute() functions. An example is as follows:

    $user = new User();
    $encryptedEmail = $user->encryptedAttribute(Input::get("email"));

Encryption and Searching

You will not be able to search on encrypted data, because it is encrypted. Comparing encrypted values would require a fixed IV which introduces security issues.

If you need to search on data then either:

  • Leave it unencrypted, or
  • Hash the data and search on the hash instead of the encrypted value. Use a well known hash algorithm such as SHA256.

You could store both a hashed and an encrypted value, use the hashed value for searching and retrieve the encrypted value for other uses.

Encryption and Authentication

The same problem with searching applies for authentication because authentication requires a user search.

If you have an authentication table where you encrypt the user data including the login data (for example the email), this will prevent Auth::attempt from working. For example this code will not work:

    $auth = Auth::attempt(array(
                "email"     =>  Input::get("email"),
                "password"  =>  Input::get("password"),
    ), $remember);

As for searching, comparing the encrypted email will not work, because it would require a fixed IV which introduces security issues.

What you will need to do instead is to hash the email address using a well known hash function (e.g. SHA256 or RIPE-MD160) rather than encrypt it, and then in the Auth::attempt function you can compare the hashes.

If you need access to the email address then you could store both a hashed and an encrypted email address, use the hashed value for authentication and retrieve the encrypted value for other uses (e.g. sending emails).

Comments
  • unpredictable decrypt behavior

    unpredictable decrypt behavior

    i'm getting seemingly random/variable decrypt behavior.

    1. some items from a table/model are decrypted while others aren't. All are in protected $encrypts array. All worked before now. No changes to elocrypt config.

    2)some items from table/model are rendered as elocrypt encrypted string(not decrypted) in view while others are not rendered at all. identical @if conditions in view. both properties exist in db as longtext elocrypted string.

    1. no errors in log from elocrypt or laravel.

    2. changes in decrypt behavior seem to happen randomly without changes being made to app code. I even have two identical apps(identical models, DB tables, controllers and views) that are currently exibiting diffferent behavior. one works fine while the other fails to decrypt all but one field.

    5)currently, elocrypt is failing to decrypt all but one property for a particular model/table. In the past it has done the opposite: decrypted all but one. never found out why. i just deleted that row and added it anew and all was fine for a while. I have no idea what is causing the breakage. This time deleting the row and re-adding didn't work. new record still has same issue.

    6)Also, elocrypt doesn't seem to work with laravel's built in password reset functionality either. IOW, laravel password reset can't read elocrypted email prop/it's not being decrypted prior to laravel trying to read it.

    thanks

    ps. php 7.0.2-2, Laravel Framework version 5.1.28 (LTS)

    opened by ITwrx 6
  • Rename 'encryptable' to 'encrypts'. Update documentation.

    Rename 'encryptable' to 'encrypts'. Update documentation.

    To be more in line with Laravel's naming conventions, I propose you rename $encryptable to $encrypts. Reads a whole lot better and makes it more explicit that we're encrypting those fields.

    opened by BrandonSurowiec 6
  • add $keys to the getAttributes() call to comply with laravel 5.3.17

    add $keys to the getAttributes() call to comply with laravel 5.3.17

    Otherwise you get this message

    ErrorException: Declaration of Delatbabel\Elocrypt\Elocrypt::getAttributes() should be compatible with Illuminate\Database\Eloquent\Model::getAttributes($keys = Array)

    opened by tomschlick 5
  • Automatic Decryption

    Automatic Decryption

    Hi I have installed delatbabel/elocryptfive and it encrypts the attributes I specify in the model, but does not decrypt them. What have I missed .... image

    opened by arnoldjp57 5
  • Manually encrypt data so I can use Elocrypt in Auth::attempt()

    Manually encrypt data so I can use Elocrypt in Auth::attempt()

    First of all, thanks for this awesome Trait. I have a db where I need to encrypt the user data including the email. And when I try to do an Auth::attempt like this:

    $auth = Auth::attempt(array(
                    "email"     =>  Input::get("email"),
                    "password"  =>  Input::get("password"),
    ), $remember);
    

    It returns an error since the email doesn't get encrypted before being passed to the attempt function. Is there a way to manually encrypt it?

    opened by yahyazini 5
  • there is a problem with search in database

    there is a problem with search in database

    Hello,

    First i want thanking you for making this great package.

    i have a problem when want using search in my project.

    i used the Elocryptfive and encrypted "postcode" column. the result of : User:find(1) is fine and shows the decrypted values but when i want using search , example : User::where('postcode','5555') it doesn't do the search and don't finding the use.(the postcode is true and available in user details)

    i think this is because that the Laravel "where" doesn't decrypt the values before searching in the database.

    please fix this issue , thanks a lot.

    opened by ghost 4
  • Add ability to customized prefix tag string

    Add ability to customized prefix tag string

    This change introduces the ability to customize the prefix string via the .env file or the published config/elocrypt.php file.

    Tests have been modified to create an app container and set the config value so it can be loaded in the model.

    opened by jdforsythe 2
  • Adding plus (+) symbol does not decrypt

    Adding plus (+) symbol does not decrypt

    We're using this package to encrypt user data which includes First Name, Last Name, Email, and Phone. When adding a plus symbol/character to the data being encrypted, it seems to encrypt correctly but does not decrypt. E.g. [email protected]

    invalid 
    opened by krisnicolaou 2
  • vendor:publish problem solved

    vendor:publish problem solved

    I had the same problem as adnanmayo in #16 . Unfortunatly you closed the issue without providing a solution so I thought I provide the solution for all the people like me who are having a problem with this.

    Instead of

    php artisan vendor:publish --provider=Delatbabel\Elocrypt\ElocryptServiceProvider

    you should use

    php artisan vendor:publish --provider='Delatbabel\Elocrypt\ElocryptServiceProvider'

    On some OS (likely windows) you need single quotes around the provider class

    opened by shrimpanse 1
  • Password reset email

    Password reset email

    With the instructions in the readme I was able to get the login working using a sha256 encryption of the email address. I made a copy of the column which was encrypted by laravel so I can always get the email address.

    With the current situation I cannot get the reset password feature to work. Any suggestions on this?

    opened by schonhose 1
  • Concern about losing key

    Concern about losing key

    Love the way the encryption work. Thank for sharing.

    I got a concern. What if I change the server. Then I would regenerate the key "php artisan key:generate" for my new server. How could I recover the encrypted data in the existing database?

    Is there any manual way to decrypt the data if I did have my "Key" and "value"?

    Thanks.

    opened by CHOMNANP 1
  • What is the actual use case of

    What is the actual use case of "ELOCRYPT_PREFIX"?

    What is the actual use case of ELOCRYPT_PREFIX?

    If the prefix can be any string, What if I use the first few chars of the APP_KEY to make the prefix dynamic?

    opened by ijasxyz 0
  • Updated the methods that overrides the base Laravel model class

    Updated the methods that overrides the base Laravel model class

    in order to support Laravel 5.5 and 5.6 (not tested on 5.7 yet)

    It should fix both #22 and #26. I didn't test it on 5.7 yet, but it should be compatible as well.

    opened by gbalduzzi 1
  • Laravel 5.6 - Data is stored as decrypted at model insert

    Laravel 5.6 - Data is stored as decrypted at model insert

    With Laravel > 5.5, this package has some issues when updating a model as mentioned in #22 . There are some possible fixes to that (i.e. overriding getDirty and castAttribute methods).

    However, I also noticed a similar issue when inserting a new record on database using Laravel 5.6.

    In Class Illuminate\Database\Eloquent\Model, the method performInsert(), has been modified from

    $attributes = $this->attributes;

    to

    $attributes = $this->getAttributes();

    So the attributes are decrypted before being saved and are therefore stored in the database as plaintext. Is there a better way to fix this issue then overriding the whole performInsert() function to just change that line?

    opened by gbalduzzi 2
  • Laravel 5.5 - data is stored as decrypted after model update

    Laravel 5.5 - data is stored as decrypted after model update

    I have been testing this package for few days on Laravel 5.5. Recently, I've checked table content and some of the rows weren't encrypted at all.

    After few tests in artisan tinker I've nailed the issue to updates that make the data unencrypted. Model creation works as expected.

    The problem happens also in default L5.5 installation, using MySQL (MariaDB 10.1.26 exactly):

    1. Database and package setup:
    composer create-project --prefer-dist laravel/laravel laravel55
    cd laravel55
    composer require delatbabel/elocryptfive
    php artisan make:auth
    php artisan migrate:fresh
    

    (if there is an error with key length, change encoding values in config/database.php to 'utf8' and 'utf8_general_ci' accordingly)

    1. Add below to app/User.php:
    use Delatbabel\Elocrypt\Elocrypt;
    
    class User extends Authenticatable
    {
        use Elocrypt;
    
       [...]
    
       protected $encrypts = [ 'name', ];
    
       [...]
    
    • add provider to ```config/app.php`
    1. Test in tinker:
    >>> User::create(['name' => 'test', 'email' => '[email protected]', 'password' => Hash::make('test')]);
    

    The value for name is encrypted.

    >>> User::find(1)->update(['email' => '[email protected]']);
    

    After the update table preview shows data as unecrypted.

    opened by bjauy 16
Releases(v1.5.6)
Owner
Del
Del
Automatically validating Eloquent models for Laravel

Validating, a validation trait for Laravel Validating is a trait for Laravel Eloquent models which ensures that models meet their validation criteria

Dwight Watson 955 Dec 25, 2022
A laravel Livewire Dynamic Selects with multiple selects depending on each other values, with infinite levels and totally configurable.

Livewire Combobox: A dynamic selects for Laravel Livewire A Laravel Livewire multiple selects depending on each other values, with infinite levels of

Damián Aguilar 25 Oct 30, 2022
A Laravel package that allows you to validate your config values and environment.

Table of Contents Overview Installation Requirements Install the Package Publishing the Default Rulesets Usage Creating a Validation Ruleset Using the

Ash Allen 152 Dec 15, 2022
Generate random typed values and in any shape.

PHP Typed Generators Description Generate random typed values and in any shape. Useful for writing your tests, there's no need to write static set of

(infinite) loophp 2 Jun 8, 2022
Update multiple Laravel Model records, each with it's own set of values, sending a single query to your database!

Laravel Mass Update Update multiple Laravel Model records, each with its own set of values, sending a single query to your database! Installation You

Jorge González 88 Dec 31, 2022
Simple address and contact management for Laravel with automatically geocoding to add longitude and latitude

Laravel Addresses Simple address and contact management for Laravel with automatically geocoding to add longitude and latitude. Installation Require t

Chantouch Sek 2 Apr 4, 2022
Is an Extension of Laravel View Class which compiles String Template on the fly. It automatically detects changes on your string template and recompiles it if needed.

Laravel-fly-view Is an Extension of Laravel View Class which compiles String Template on the fly. It automatically detects changes on your string temp

John Turingan 16 Jul 17, 2022
Searches for multilingual phrases in Laravel project and automatically generates language files for you.

Laravel Lang Generator Searches for multilingual phrases in a Laravel project and automatically generates language files for you. You can search for n

Gleb 5 Oct 19, 2022
Automatically disable Google's FLoC in Laravel apps

Automatically disable Google's FLoC in Laravel apps This package will automatically disable Google's FLoC. Support us We invest a lot of resources int

Spatie 68 Oct 21, 2022
Automatically load your helpers in your laravel application.

Laravel AutoHelpers Automatically load your helpers in your laravel application. Installation You can install the package via composer: composer requi

Florian Wartner 6 Jul 26, 2021
Automatically generate ERD Diagrams from Model's relations in Laravel

Laravel ERD Generator Automatically generate interactive ERD from Models relationships in Laravel. This package provides a CLI to automatically genera

Pulkit Kathuria 90 Dec 29, 2022
Laravel Migrations Generator: Automatically generate your migrations from an existing database schema.

Laravel Migrations Generator Generate Laravel Migrations from an existing database, including indexes and foreign keys! This package is cloned from ht

Kit Loong 1.4k Jan 1, 2023
Package to optimize your site automatically which results in a 35%+ optimization

Laravel Page Speed Simple package to minify HTML output on demand which results in a 35%+ optimization. Laravel Page Speed was created by Renato Marin

Renato Marinho 2.2k Dec 28, 2022
A tool to automatically fix PHP Coding Standards issues by Dragon Code.

The Dragon Code Styler Installation Required PHP: ^8.0 Composer: ^2.0 Locally composer global require dragon-code/codestyler Usage When you run the co

The Dragon Code 24 Aug 27, 2022
Fast and simple implementation of a REST API based on the Laravel Framework, Repository Pattern, Eloquent Resources, Translatability, and Swagger.

Laravel Headless What about? This allows a fast and simple implementation of a REST API based on the Laravel Framework, Repository Pattern, Eloquent R

Julien SCHMITT 6 Dec 30, 2022
This Laravel package merges staudenmeir/eloquent-param-limit-fix and staudenmeir/laravel-adjacency-list to allow them being used in the same model.

This Laravel package merges staudenmeir/eloquent-param-limit-fix and staudenmeir/laravel-adjacency-list to allow them being used in the same model.

Jonas Staudenmeir 5 Jan 6, 2023
Stop duplicating your Eloquent query scopes and constraints in PHP. This package lets you re-use your query scopes and constraints by adding them as a subquery.

Laravel Eloquent Scope as Select Stop duplicating your Eloquent query scopes and constraints in PHP. This package lets you re-use your query scopes an

Protone Media 75 Dec 7, 2022
An Eloquent Way To Filter Laravel Models And Their Relationships

Eloquent Filter An Eloquent way to filter Eloquent Models and their relationships Introduction Lets say we want to return a list of users filtered by

Eric Tucker 1.5k Jan 7, 2023
Laravel Ban simplify blocking and banning Eloquent models.

Laravel Ban Introduction Laravel Ban simplify management of Eloquent model's ban. Make any model bannable in a minutes! Use case is not limited to Use

cybercog 879 Dec 30, 2022