bobkosse/laravel-data-security
最新稳定版本:1.0.0
Composer 安装命令:
composer require bobkosse/laravel-data-security
包简介
Easy to use data security solution for Laravel
README 文档
README
This package provides a lightweight solution for handling sensitive data within Laravel Eloquent models. It automatically encrypts specific fields, decrypts them only when explicitly requested, supports searching encrypted data through blind indexes, and includes audit and migration tooling to manage privacy coverage across your application.
Table of Contents
- Features
- Requirements
- Installation
- Configuration
- Usage
- Commands
- How it works internally
- Important notes
- Testing
- Contributing
- License
- AI Assistance
Features
- Automatic field encryption: Encrypts sensitive model attributes before they are stored in the database.
- Automatic field decryption: Decrypts privacy fields only when privacy is explicitly revealed.
- Safe default masking: Privacy fields return
[ENCRYPTED]by default to prevent accidental data exposure. - Searchable encrypted data: Optional blind indexes let you query encrypted values without decrypting them.
- Bulk write support: Works with model-based bulk operations such as
insert(),insertOrIgnore(),upsert(), andwhere()->update(). - Duplicate encryption protection: Prevents already encrypted values from being encrypted again.
- Clear decryption errors: Throws a
PrivacyDecryptionExceptionwhen encrypted values cannot be decrypted. - Configurable model exclusions: Skip models by class-name suffix (the
Usermodel is excluded by default). - Privacy audit command: Scans your models and reports which ones use the privacy trait and which privacy fields they define.
- Interactive encryption command: Encrypt existing data for newly added privacy fields and optionally create a blind index.
- Attribute-based configuration: Use PHP 8 attributes for cleaner model definitions.
Requirements
- PHP 8.3 or higher
- Laravel (Eloquent) — see
composer.jsonfor the supported framework version - A configured Laravel application encryption key (
APP_KEY), since encryption relies on Laravel's encrypter
Installation
Install the package via Composer:
composer require bobkosse/laravel-data-security
The service provider is auto-discovered through Laravel's package discovery, so no manual registration is required. Both console commands (privacy:audit and privacy:encrypt-field) are registered automatically when running in the console.
Configuration
The package ships with a configuration file that is merged automatically. It exposes two options:
return [
// The paths that are scanned when looking for Eloquent models
// (used by the privacy:encrypt-field command).
'paths' => [
app_path('Models'),
],
// Models whose class name ends with one of these suffixes are
// excluded from privacy handling and from scanning.
'excludedSuffixes' => ['User'],
];
paths— Directories scanned for Eloquent models by the interactive encrypt-field command. Add more paths if your models live outsideapp/Models.excludedSuffixes— Any model whose class name ends with one of these suffixes is skipped. By default this protects theUsermodel so authentication data is never accidentally encrypted. Add your own suffixes here to exclude additional models.
If you need to customize these values, copy the package's
data-security.phpinto your application'sconfigdirectory and adjust it there.
Usage
1. Prepare your model
Add the HasPrivacy trait to any Eloquent model containing sensitive data. Define the fields that should be protected using the #[Protect] attribute.
use BobKosse\DataSecurity\Attributes\Protect;
use BobKosse\DataSecurity\Traits\HasPrivacy;
use Illuminate\Database\Eloquent\Model;
#[Protect(fields: ['phone_number', 'address', 'social_security_number'])]
class PatientProfile extends Model
{
use HasPrivacy;
}
2. How it works
Saving data
When a value is assigned to a field listed in the #[Protect] attribute, the trait automatically encrypts it before it reaches the database. Values that are already encrypted are detected and left untouched, preventing double encryption. This works for both single-model and bulk Eloquent writes:
fill()create()save()update()forceFill()insert()insertOrIgnore()upsert()where()->update()
Reading data
By default, privacy fields return [ENCRYPTED] when accessed, preventing accidental exposure of sensitive data.
Revealing data
To access the decrypted value, explicitly reveal privacy first.
use BobKosse\DataSecurity\Exceptions\PrivacyDecryptionException;
$profile = PatientProfile::find(1);
// Returns "[ENCRYPTED]"
echo $profile->phone_number;
// Reveal privacy to access the decrypted value
$profile->revealPrivacy(true);
// Returns the decrypted value (e.g., "+31 6 12345678")
echo $profile->phone_number;
You can also hide the data again by passing false:
$profile->revealPrivacy(false);
This pairs well with authorization policies, ensuring sensitive data is only revealed to authorized users:
$profile = PatientProfile::find(1);
if ($user->can('viewSensitiveData', $profile)) {
$profile->revealPrivacy(true);
}
return $profile->phone_number;
If an encrypted value cannot be decrypted (for example, after a key rotation), a PrivacyDecryptionException is thrown so the failure is explicit rather than silent.
3. Searching encrypted data (blind index)
Because encrypted values are not directly searchable, the package supports blind indexes. A blind index stores a deterministic hash of a field in a companion blind_<field> column, allowing you to look up records by an exact value without ever decrypting the stored data.
Once a blind index exists for a field (see the encrypt-field command below), query it using the helper methods provided by the trait:
// Find records matching an exact value, without decrypting the column
PatientProfile::query()
->whereBlindIndex('phone_number', '+31 6 12345678')
->get();
// searchBlindIndex() is an expressive alias of whereBlindIndex()
PatientProfile::query()
->searchBlindIndex('phone_number', '+31 6 12345678')
->get();
Blind indexes support exact-match lookups only. Partial matches, ranges, and LIKE queries are not possible against encrypted data.
4. HasPrivacy works on Eloquent models
The trait is designed for Eloquent models and does not affect raw database queries. All standard Eloquent reads and writes are supported, including the single-model and bulk operations listed under Saving data.
Commands
Privacy Audit Command
Scans a directory for Eloquent models and reports which ones use the privacy trait.
php artisan privacy:audit app/Models
The command shows:
- Model: the full class name of the model
- Has Privacy Trait: whether the trait is implemented
- Privacy Fields: the fields currently configured for encryption
If no directory is provided, it defaults to app/Models. Both relative paths (resolved from the application base path) and absolute paths are supported.
Privacy Encrypt Field Command
When you want to add privacy protection to an existing field that already contains plain-text data, use this command to encrypt the existing values. The command will automatically add the correct attributes and trait to the model (if not present)
php artisan privacy:encrypt-field
This interactive command will:
- Select a model — choosing from the Eloquent models found in the directories configured under
paths. - Select a field — system fields (such as
id,created_at,updated_at,deleted_at, and the privacy identifier) and already-protected fields are excluded from the list. - Detect already-encrypted data — if the selected field already appears encrypted, the command offers to register the field in the model's
#[Protect]attribute without re-encrypting the existing data. - Update the model file — adding the field to the
#[Protect]attribute (and theHasPrivacytrait) if it is missing. - Encrypt existing values — encrypting all existing plain-text values for that field in the database, in chunks, within a transaction. Already-encrypted and
nullvalues are skipped. - Optionally create a blind index — when confirmed, it adds a
blind_<field>column to the table and backfills blind-index hashes for existing records, so the field remains searchable viawhereBlindIndex().
Finally, the command prints a summary report showing the model, the field, the number of records encrypted, and the current list of encrypted fields for that model.
How it works internally
This section is aimed at contributors and advanced users; it describes implementation details rather than the public API.
Encryption layer
Encryption uses Laravel's configured encrypter. The package never stores plain-text once a value is assigned to a protected field, and it guards against double encryption by checking whether a value can already be decrypted before encrypting it again.
Blind index hashing
A blind index is a deterministic SHA-256 hash of a field's value, stored in a blind_<field> column. Because the same input always produces the same hash, exact-match lookups are possible without decryption. The hash is intentionally one-way, so the original value cannot be recovered from the index column.
Bloom filter (internal optimization)
To support fast "does this value already exist?" checks, the package includes a Bloom filter — a probabilistic, memory-efficient data structure. It is configured with a bit-array size and a number of hash functions (defaulting to a size of 10000 and 3 hashes) and exposes an estimated false-positive rate.
A Bloom filter can produce false positives (it may report that a value might exist when it does not) but never false negatives (if it reports a value is absent, it is definitively absent). It is therefore used only as a fast pre-check; authoritative existence is always confirmed against the database. Note that the default Bloom filter instance is in-memory and per-request, so it functions as an internal optimization rather than a persistent cache.
Important notes
- Configurable model exclusions: Models are skipped based on the
excludedSuffixesconfiguration. The defaultUsersuffix prevents the framework's authentication model from being encrypted. Adjust this list to suit your application. - Database column size: Ensure privacy columns can store encrypted strings, typically using
TEXTorBLOB. - Blind index columns: Creating a blind index adds a
blind_<field>column to the table. Make sure your schema can accommodate it. Blind indexes support exact-match lookups only. - Application key: Encryption depends on Laravel's
APP_KEY. Rotating the key without re-encrypting existing data will cause decryption to fail with aPrivacyDecryptionException. - Raw SQL is out of scope: Direct
DB::table()queries or raw SQL statements bypass the trait and will not be encrypted, decrypted, or indexed automatically.
Testing
This package uses Pest. Run the test suite with:
composer test
or directly:
vendor/bin/pest
Contributing
Contributions are welcome. Please ensure new code is covered by tests and passes the static analysis and code-style checks (PHPStan/Larastan and Laravel Pint) before opening a pull request.
License
This package is open-sourced software licensed under the MIT license.
统计信息
- 总下载量: 1
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 13
- 依赖项目数: 0
- 推荐数: 0
其他信息
- 授权协议: MIT
- 更新时间: 2026-04-20