wazza / laravel-db-encryption
A Laravel package that helps encrypt & decrypt certain defined table columns ensuring the data is secure in the database but can be accessed by the models.
Requires
- php: ^8.2 || ^8.3
- ext-json: *
- illuminate/support: ^12.0
Requires (Dev)
- fakerphp/faker: ^1.20.0
- laravel/legacy-factories: ~1
- mockery/mockery: ^1.2
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.8
- pestphp/pest-plugin-laravel: ^3.2
- phpunit/phpunit: ^11.0
This package is auto-updated.
Last update: 2025-06-13 17:34:42 UTC
README
A Laravel package for secure, transparent encryption and decryption of sensitive model attributes, storing them in a dedicated table while keeping your main tables clean and fast.
Features
- Seamless encryption/decryption of model attributes via a simple trait
- Encrypted data is stored in a separate
encrypted_attributes
table - Only non-table attributes can be encrypted (enforced at runtime)
- Automatic loading and saving of encrypted attributes using Eloquent events
- Search/filter on encrypted properties using SHA-256 hash
- No sensitive values are ever logged
- Easy integration: just add the trait and define
$encryptedProperties
in your model - Compatible with Laravel 9+
Requirements
- PHP 8.1+
- Laravel 9 or higher
- OpenSSL PHP extension
How It Works
- Add the
HasEncryptedAttributes
trait to your Eloquent model. - Define a public array property
$encryptedProperties
listing the attributes you want encrypted (these must NOT exist as columns in the model's table). - When you load a model, encrypted attributes are automatically decrypted and available as normal properties.
- When you save a model, encrypted attributes are removed from the main table and securely stored in the
encrypted_attributes
table. - You can filter/search on encrypted properties using the provided query scope.
Example Model:
use Wazza\DbEncrypt\Traits\HasEncryptedAttributes; class User extends Model { use HasEncryptedAttributes; protected $fillable = ['name', 'email']; // Only non-table attributes can be encrypted! public array $encryptedProperties = [ 'social_security_number', 'private_note', ]; }
Usage
- Use your model as normal:
$user = User::find(1); $user->social_security_number = '123-45-6789'; $user->private_note = 'Sensitive info'; $user->save(); // When you retrieve the user again, encrypted attributes are automatically decrypted: $user = User::find(1); echo $user->social_security_number; // '123-45-6789'
- If you try to add an attribute to
$encryptedProperties
that already exists as a column, an exception will be thrown.
Filtering/Search on Encrypted Properties
You can filter or search for models by encrypted property value using the built-in query scope:
// Find users with a specific social security number $users = User::whereEncrypted('social_security_number', '123-45-6789')->get();
This uses the SHA-256 hash of the value and joins the encrypted_attributes
table for efficient searching, without ever exposing the decrypted value in the query or logs.
Installation Steps
- Require the package in your Laravel project:
composer require wazza/laravel-db-encryption
- Publish the config and migration files (if needed):
php artisan vendor:publish --provider="Wazza\DbEncrypt\DbEncryptServiceProvider"
- Run the migration to create the
encrypted_attributes
table:php artisan migrate
- Add the trait and
$encryptedProperties
to your models as shown above.
Monitoring & Logs
- All encryption/decryption operations are logged (without sensitive values).
- To monitor package logs:
tail -f storage/logs/laravel.log | grep db-encrypt
Testing
- Run the test suite using Pest:
./vendor/bin/pest PASS Tests\Unit\EncryptorTest ✓ it correctly hashes the value 0.40s ✓ it correctly encrypts and decrypts data 0.15s ✓ it returns different ciphertext for same plaintext (random IV) 0.12s ✓ it throws on null input for encrypt 0.13s ✓ it throws on null input for decrypt 0.13s ✓ it throws on invalid base64 for decrypt 0.14s ✓ it throws on missing key in config 0.19s PASS Tests\Unit\ExampleTest ✓ that true is true 0.28s PASS Tests\Feature\ExampleTest ✓ it contains a successful example feature test 0.18s Tests: 9 passed (9 assertions) Duration: 1.98s
- Ensure your models and encrypted attributes behave as expected.
For more details, see the source code and comments. Contributions and issues welcome!