spatie / laravel-ciphersweet by spatie

Use ciphersweet in your Laravel project
389,787
359
9
Package Data
Maintainer Username: spatie
Maintainer Contact: rias@spatie.be (Rias Van der Veken)
Package Create Date: 2022-06-28
Package Last Update: 2024-07-22
Home Page: https://spatie.be/open-source
Language: PHP
License: MIT
Last Refreshed: 2024-11-21 03:01:38
Package Statistics
Total Downloads: 389,787
Monthly Downloads: 16,979
Daily Downloads: 756
Total Stars: 359
Total Watchers: 9
Total Forks: 32
Total Open Issues: 1

Use CipherSweet in your Laravel project

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

In your project, you might store sensitive personal data in your database. Should an unauthorised person get access to your DB, all sensitive can be read which is obviously not good.

To solve this problem, you can encrypt the personal data. This way, unauthorized persons cannot read it, but your application can still decrypt it when you need to display or work with the data.

CipherSweet is a backend library developed by Paragon Initiative Enterprises for implementing searchable field-level encryption. It can encrypt and decrypt values in a very secure way. It is also able to create blind indexes. These indexes can be used to perform searches on encrypted data. The indexes themselves are unreadable by humans.

Our package is a wrapper over CipherSweet, which allows you to easily use it with Laravel's Eloquent models.

Support us

We invest a lot of resources into creating best in class open source packages. You can support us by buying one of our paid products.

We highly appreciate you sending us a postcard from your hometown, mentioning which of our package(s) you are using. You'll find our address on our contact page. We publish all received postcards on our virtual postcard wall.

Installation

You can install the package via composer:

composer require spatie/laravel-ciphersweet

You must publish and run the migrations with:

php artisan vendor:publish --tag="ciphersweet-migrations"
php artisan migrate

Optionally, you can publish the config file with:

php artisan vendor:publish --tag="ciphersweet-config"

This is the contents of the config file:

return [
    /*
     * This controls which cryptographic backend will be used by CipherSweet.
     * Unless you have specific compliance requirements, you should choose
     * "nacl".
     *
     * Supported: "boring", "fips", "nacl"
     */

    'backend' => env('CIPHERSWEET_BACKEND', 'nacl'),

    /*
     * Select which key provider your application will use. The default option
     * is to read a string literal out of .env, but it's also possible to
     * provide the key in a file or use random keys for testing.
     *
     * Supported: "file", "random", "string"
     */

    'provider' => env('CIPHERSWEET_PROVIDER', 'string'),

    /*
     * Set provider-specific options here. "string" will read the key directly
     * from your .env file. "file" will read the contents of the specified file
     * to use as your key. "custom" points to a factory class that returns a
     * provider from its `__invoke` method. Please see the docs for more details.
     */
    'providers' => [
        'file' => [
            'path' => env('CIPHERSWEET_FILE_PATH'),
        ],
        'string' => [
            'key' => env('CIPHERSWEET_KEY'),
        ],
    ],
];

Usage

Few steps are involved to store encrypted values. Let's go through them.

1. Preparing your model and choosing the attributes that should be encrypted

Add the CipherSweetEncrypted interface and UsesCipherSweet trait to the model that you want to add encrypted fields to.

You'll need to implement the configureCipherSweet method to configure CipherSweet.

use Spatie\LaravelCipherSweet\Contracts\CipherSweetEncrypted;
use Spatie\LaravelCipherSweet\Concerns\UsesCipherSweet;
use ParagonIE\CipherSweet\EncryptedRow;
use Illuminate\Database\Eloquent\Model;

class User extends Model implements CipherSweetEncrypted
{
    use UsesCipherSweet;
    
    /**
     * Encrypted Fields
     *
     * Each column that should be encrypted should be added below. Each column
     * in the migration should be a `text` type to store the encrypted value.
     *
     * ```
     * ->addField('column_name')
     * ->addBooleanField('column_name')
     * ->addIntegerField('column_name')
     * ->addTextField('column_name')
     * ```
     *
     * A JSON array can be encrypted as long as the key structure is defined in
     * a field map. See the docs for details on defining field maps.
     *
     * ```
     * ->addJsonField('column_name', $fieldMap)
     * ```
     *
     * Each field that should be searchable using an exact match needs to be
     * added as a blind index. Partial search is not supported. See the docs
     * for details on bit sizes and how to use compound indexes.
     *
     * ```
     * ->addBlindIndex('column_name', new BlindIndex('column_name_index'))
     * ```
     *
     * @see https://github.com/spatie/laravel-ciphersweet
     * @see https://ciphersweet.paragonie.com/
     * @see https://ciphersweet.paragonie.com/php/blind-index-planning
     * @see https://github.com/paragonie/ciphersweet/blob/master/src/EncryptedRow.php
     *
     * @param EncryptedRow $encryptedRow
     *
     * @return void
     */
    public static function configureCipherSweet(EncryptedRow $encryptedRow): void
    {
        $encryptedRow
            ->addField('email')
            ->addBlindIndex('email', new BlindIndex('email_index'));
    }
}

The example above will encrypt the email field on the User model. It also adds a blind index in the blind_indexes table which allows you to search on it.

Check out the CipherSweet PHP docs for more information on what is possible.

2. Generating the encrypting key

An encryption key is used to encrypt your values. You can generate a new CipherSweet encrypting key using this command:

php artisan ciphersweet:generate-key

3. Encrypting model attributes

With this in place, you can run this command to encrypt all values:

php artisan ciphersweet:encrypt <your-model-class> <generated-key>

The command will update all the encrypted fields and blind indexes of the model.

If you have a lot of rows, this process can take a long time. The command is restartable: it can be re-run without needing to re-encrypt already rotated keys.

4. Updating your .env file

After the fields have been encrypted, you should add the generated CipherSweet key to your .env file.

CIPHERSWEET_KEY=<YOUR-KEY>

The key will be used by your application to read encrypted values.

Searching on blind indexes

Even though values are encrypted, you can still search them using a blind index. The blind indexes will have been built up when you ran the command to encrypt the model values.

This package provides a whereBlind and orWhereBlind scope to search on blind indexes.

The first parameter is the column, the second the index name you set up when calling ->addBlindIndex, the third is the raw value, the package will automatically apply any transformations and hash the value to search on the blind index.

$user = User::whereBlind('email', 'email_index', 'rias@spatie.be');

Rotating keys

Should you suspect that somebody got a hold of your encrypting key, you can re-encrypt the values. Simply generate another encrypting key, and run the php artisan ciphersweet:encrypt command again.

php artisan ciphersweet:encrypt "App\User" <your-new-key>

This will update all the encrypted fields and blind indexes of the model. Once this is done, you can update your environment or config file to use the new key.

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.