wazza/laravel-db-encryption 问题修复 & 功能扩展

解决BUG、新增功能、兼容多环境部署,快速响应你的开发需求

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

wazza/laravel-db-encryption

最新稳定版本:v1.0.0

Composer 安装命令:

composer require wazza/laravel-db-encryption

包简介

Production-ready Laravel package for secure, transparent encryption of sensitive model attributes with searchable hash indexes and key rotation support.

README 文档

README

GitHub Actions GitHub issues GitHub stars GitHub license GitHub version Buy me a coffee

Laravel DB Encryption

A production-ready Laravel package for secure, transparent encryption of sensitive model attributes. Store encrypted data in a dedicated table while keeping your main tables clean and performant.

🔐 Why This Package?

  • Transparent Encryption: Automatic encryption/decryption via Eloquent trait
  • Separate Storage: Encrypted data stored in dedicated encrypted_attributes table
  • Searchable: Filter encrypted data using SHA-256 hash indexes
  • Zero Configuration: Works out of the box with sensible defaults
  • Production Ready: Comprehensive error handling, logging, and security features
  • Performance: Batch operations and optimized queries
  • Compliance Ready: Helps meet GDPR, HIPAA, PCI DSS requirements

📋 Requirements

  • PHP: 8.2 or higher
  • Laravel: 12.x
  • OpenSSL: PHP OpenSSL extension

🚀 Installation

1. Install via Composer

composer require wazza/laravel-db-encryption

2. Publish Configuration & Migrations

# Publish config file
php artisan vendor:publish --provider="Wazza\DbEncrypt\Providers\DbEncryptServiceProvider" --tag="db-encrypt-config"

# Publish migrations
php artisan vendor:publish --provider="Wazza\DbEncrypt\Providers\DbEncryptServiceProvider" --tag="db-encrypt-migrations"

3. Generate Encryption Key

php artisan db-encrypt:generate-key

This adds DB_ENCRYPT_KEY to your .env file.

4. Run Migrations

php artisan migrate

📖 Usage

Basic Setup

Add the HasEncryptedAttributes trait to your model and define which attributes should be encrypted:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Wazza\DbEncrypt\Traits\HasEncryptedAttributes;

class User extends Model
{
    use HasEncryptedAttributes;

    protected $fillable = ['name', 'email', 'phone'];

    /**
     * Attributes that should be encrypted.
     * These MUST NOT exist as columns in your table!
     */
    public array $encryptedProperties = [
        'social_security_number',
        'credit_card_number',
        'medical_record',
    ];
}

Working with Encrypted Attributes

// Create a user with encrypted attributes
$user = User::create([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'social_security_number' => '123-45-6789',
    'credit_card_number' => '4111-1111-1111-1111',
]);

// Encrypted attributes work like normal properties
echo $user->social_security_number; // '123-45-6789' (automatically decrypted)

// Update encrypted attributes
$user->social_security_number = '987-65-4321';
$user->save();

// Retrieve and use
$user = User::find(1);
echo $user->social_security_number; // Automatically decrypted!

Searching Encrypted Data

Use the whereEncrypted scope to search encrypted attributes:

// Find users by encrypted SSN
$users = User::whereEncrypted('social_security_number', '123-45-6789')->get();

// Find specific user
$user = User::whereEncrypted('credit_card_number', '4111-1111-1111-1111')->first();

// Combine with other queries
$users = User::where('email', 'like', '%@example.com%')
    ->whereEncrypted('social_security_number', '123-45-6789')
    ->get();

Using the Facade

For direct encryption/decryption operations:

use Wazza\DbEncrypt\Facades\DbEncrypt;

// Encrypt a value
$encrypted = DbEncrypt::encrypt('sensitive data');

// Decrypt a value
$decrypted = DbEncrypt::decrypt($encrypted);

// Generate search hash
$hash = DbEncrypt::hash('search value');

// Batch operations
$encrypted = DbEncrypt::encryptBatch([
    'ssn' => '123-45-6789',
    'cc' => '4111-1111-1111-1111',
]);

// Verify without decrypting
$isMatch = DbEncrypt::verify('original text', $encryptedValue);

🛠️ Advanced Features

Artisan Commands

Generate Encryption Key

# Generate and set new key in .env
php artisan db-encrypt:generate-key

# Just display the key without saving
php artisan db-encrypt:generate-key --show

Re-encrypt Data (Key Rotation)

# Re-encrypt all encrypted attributes
php artisan db-encrypt:re-encrypt

# Dry run to see what would happen
php artisan db-encrypt:re-encrypt --dry-run

# Re-encrypt specific table only
php artisan db-encrypt:re-encrypt --table=users

# Process in smaller batches
php artisan db-encrypt:re-encrypt --batch=50

Prune Orphaned Records

# Remove encrypted attributes for deleted models
php artisan db-encrypt:prune

# Dry run
php artisan db-encrypt:prune --dry-run

# Prune specific table
php artisan db-encrypt:prune --table=users

Configuration

Edit config/db-encrypt.php:

return [
    // Logging configuration
    'logging' => [
        'level' => env('DB_ENCRYPT_LOG_LEVEL', 0), // 0=None, 1=High, 2=Mid, 3=Low
        'indicator' => env('DB_ENCRYPT_LOG_INDICATOR', 'db-encrypt'),
    ],

    // Encryption key
    'key' => env('DB_ENCRYPT_KEY'),

    // Database configuration
    'db' => [
        'primary_key_format' => env('DB_ENCRYPT_DB_PRIMARY_KEY_FORMAT', 'int'), // 'int' or 'uuid'
    ],
];

Custom Exceptions

The package provides specific exceptions for better error handling:

use Wazza\DbEncrypt\Exceptions\EncryptionException;
use Wazza\DbEncrypt\Exceptions\DecryptionException;
use Wazza\DbEncrypt\Exceptions\InvalidAttributeException;
use Wazza\DbEncrypt\Exceptions\ModelNotSetException;

try {
    $encrypted = DbEncrypt::encrypt($value);
} catch (EncryptionException $e) {
    // Handle encryption failure
    Log::error('Encryption failed: ' . $e->getMessage());
}

🔒 Security Best Practices

1. Key Management

  • Never commit encryption keys to version control
  • Use different keys for each environment
  • Rotate keys periodically using db-encrypt:re-encrypt
  • Consider using a Key Management Service (KMS) in production

2. What to Encrypt

Good candidates:

  • Social Security Numbers
  • Credit card numbers
  • Passwords (though hashing is usually better)
  • Medical records
  • Personal identification numbers
  • Private notes

Bad candidates:

  • Primary keys or foreign keys
  • Data you need to sort by
  • Data used in mathematical operations
  • High-cardinality lookup values

3. Performance Considerations

  • Encryption adds overhead—only encrypt truly sensitive data
  • Use indexes on your main tables for performance
  • Consider caching decrypted data for read-heavy operations
  • Use batch operations when encrypting/decrypting multiple values

4. Backup Strategy

  • Always backup before key rotation
  • Test key rotation in staging first
  • Keep old keys until you verify re-encryption succeeded

See SECURITY.md for comprehensive security guidelines.

🧪 Testing

# Run all tests
./vendor/bin/pest

# Run with coverage
./vendor/bin/pest --coverage

# Run specific test file
./vendor/bin/pest tests/Unit/EncryptorTest.php

🐛 Troubleshooting

"Encryption key is not set"

Solution: Run php artisan db-encrypt:generate-key or manually set DB_ENCRYPT_KEY in .env

"Cannot encrypt attribute 'name' because it exists as a column"

Solution: Encrypted properties must NOT exist as database columns. Remove the column or choose a different property name.

"Decryption failed"

Possible causes:

  • Wrong encryption key
  • Corrupted data
  • Key was rotated but data wasn't re-encrypted

Solution:

  1. Verify DB_ENCRYPT_KEY is correct
  2. Check logs for detailed error messages
  3. Restore from backup if data is corrupted

Performance issues

Solutions:

  • Ensure indexes are created on encrypted_attributes table (done automatically)
  • Reduce logging level in production (DB_ENCRYPT_LOG_LEVEL=0)
  • Use batch operations for multiple encryptions
  • Consider caching frequently accessed encrypted data

Search not finding records

Check:

  • Ensure you're using whereEncrypted() scope
  • Verify the exact value (encryption is case-sensitive)
  • Check that hash_index was generated correctly

📊 Monitoring

View Package Logs

# Real-time log monitoring
tail -f storage/logs/laravel.log | grep db-encrypt

# Search for errors
grep "db-encrypt.*error" storage/logs/laravel.log

Check Encryption Status

use Wazza\DbEncrypt\Helper\Encryptor;

// Get encryption info
$info = Encryptor::getInfo();
/*
[
    'method' => 'AES-256-CBC',
    'hash_algorithm' => 'sha512',
    'search_hash_algorithm' => 'sha256',
    'iv_length' => 16,
    'supported' => true,
    'key_configured' => true,
]
*/

// Check if encryption is supported
if (!Encryptor::isSupported()) {
    throw new Exception('OpenSSL not available');
}

🤝 Contributing

Contributions are welcome! Please see CONTRIBUTING.md for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Write tests for your changes
  4. Ensure all tests pass (./vendor/bin/pest)
  5. Commit your changes (git commit -m 'Add amazing feature')
  6. Push to the branch (git push origin feature/amazing-feature)
  7. Open a Pull Request

📜 License

This package is open-sourced software licensed under the MIT license.

👨‍💻 Author

Warren Coetzee

🙏 Acknowledgments

  • Built for the Laravel community
  • Inspired by the need for simple, secure database encryption
  • Thanks to all contributors and users

☕ Support

If this package helps you, consider buying me a coffee!

📝 Changelog

See CHANGELOG.md for what has changed recently.

🛡️ Security

Please review our security policy for reporting security vulnerabilities.

Made with ❤️ for the Laravel community

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 2
  • 点击次数: 4
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 2
  • Watchers: 1
  • Forks: 2
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2025-06-13

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固