madmatt / silverstripe-encrypt-at-rest
启用数据库中数据的静态加密
Requires
- php: ^8.0
- defuse/php-encryption: ^2.2
- silverstripe/framework: ^5
Requires (Dev)
- phpunit/phpunit: ^9.6
This package is auto-updated.
Last update: 2024-09-12 22:10:44 UTC
README
此模块允许在存储到数据库之前加密 Silverstripe CMS ORM 数据,并在应用中使用前自动解密。为此,我们使用只有 web 服务器才知道的密钥。
需要了解的注意事项
- 需要注意的是,此模块并不能完全保证您数据的安全性。只有当您完全理解此模块的运作方式时,才应将其用作保护措施。在大多数情况下,加密整个数据库既充分又同样有效。只有当您的分层保护策略需要并允许时,才使用此模块来加密静态数据(逐字段加密)。明确来说,在加密静态数据时,必须在使用之前解密数据。在几乎所有情况下,托管网站的 web 服务器比数据库服务器更容易受到攻击,这意味着如果攻击者能够入侵您的 web 服务器,他们将能够访问数据库和用于加密数据的密钥。
- 逐字段加密和解密数据会产生性能开销,可能会在项目中产生不良结果。
- 此模块在底层使用
defuse/php-encryption
库,该库更重视安全性而不是性能。在DataObject
上加密大量字段可能会显著降低读取或写入大量数据(例如 CMS 中的ModelAdmin
视图,一次渲染 50+ 条记录)的操作速度(仅解密字段就可能需要几秒钟的处理时间)。应确保仅加密最少的数据集,并且这些数据不需要频繁使用。
要求
- SilverStripe CMS 5.0
安装
通过 Composer 安装
composer require madmatt/silverstripe-encrypt-at-rest
安装完成后,您需要生成一个将用于加密所有数据的密钥。
- 使用
vendor/bin/generate-defuse-key
生成一个十六进制密钥(由defuse/php-encryption
提供的工具)。这将输出一个以def
开头的 ASCII 安全密钥。 - 将此密钥设置为环境变量
ENCRYPT_AT_REST_KEY
。
对于开发环境,您可以在 .env
中设置此变量,例如
ENCRYPT_AT_REST_KEY="{generated defuse key}"
有关更多信息,请参阅 SilverStripe 环境管理。
使用方法
在您的 DataObject
中,使用加密字段类型创建新的数据库字段。注意:不支持将已包含数据的现有字段转换为加密字段。这可能 可能 会工作,但不能保证。您应该通过创建新字段并创建一个任务来映射旧字段到新加密字段(如果需要)来迁移您的数据。
例如
use Madmatt\EncryptAtRest\FieldType\EncryptedVarchar; class SecureDataObject extends DataObject { private static $db = [ 'NormalText' => 'Varchar' 'SecureText' => EncryptedVarchar::class ]; }
查看 src/FieldType
文件夹以获取所有字段类型,或查看以下列表
Madmatt\EncryptAtRest\FieldType\EncryptedDatetime
Madmatt\EncryptAtRest\FieldType\EncryptedDecimal
Madmatt\EncryptAtRest\FieldType\EncryptedEnum
Madmatt\EncryptAtRest\FieldType\EncryptedInt
Madmatt\EncryptAtRest\FieldType\EncryptedText
Madmatt\EncryptAtRest\FieldType\EncryptedVarchar
注意:在数据库中保存时,所有这些加密字段都存储为TEXT
列类型。这是因为加密数据的长度通常比原始文本字符串长得多。它们不会占用表列空间,但当许多字段包含在内时,会导致查询执行时间更长,因为数据库需要从单独的blob存储中检索所有这些字段。
注意2:这些字段都扩展自基本数据类型(例如,EncryptedDatetime extends DBDatetime
),因此大多数常见的字段辅助方法都可以使用(例如,$DatetimeField.Ago
)。
当值写入数据库时,数据将自动加密,并且每当从数据库读取该数据时,它都会被解密。
要使用解密值,您只需像在其他任何上下文中一样使用该值即可。例如
// Via DataObject::get() $obj = SecureDataObject::get()->first()->SecureText; // Returns the decrypted string from the field // Getting the DB field $obj = SecureDataObject::get()->first(); $field = $obj->dbObject('SecureText'); // Returns an EncryptedVarchar object $uppercase = $field->UpperCase(); // Method on DBString, returns a string
在Silverstripe模板中的使用也非常简单
<% loop $SecureDataObjects %> <p>$SecureText.UpperCase</p> <% end_loop %>
如果您已使用此模块的Silverstripe CMS 3版本,您就不再需要依赖->getDecryptedValue()
方法——在访问时值始终会被解密。
在不使用ORM的情况下加密和解密任意文本字符串和文件
您还可以在不使用Silverstripe ORM的情况下加密/解密任意文本字符串以及整个文件系统上的整个文件(例如,不使用DataObject
)。例如,您可能想这样做是为了安全地与API通信。
use Madmatt\EncryptAtRest\AtRestCryptoService; use SilverStripe\Assets\File; use SilverStripe\Core\Injector\Injector; $text = 'This is an unencrypted string!'; /** @var AtRestCryptoService $service */ $service = Injector::inst()->get(AtRestCryptoService::class); $encryptedText = $service->encrypt($text); // Returns encrypted string starting with `def` $unencryptedText = $service->decrypt($encryptedText); // Returns 'This is an unencrypted string!' $file = File::get()->byID(1); // Presume this is a file that contains the text string above // This will encrypt the file contents, delete the original file from the filesystem and create a new file at the same path with .enc appended to the filename $encryptedFile = $service->encryptFile($file); // This will decrypt the file contents, delete the encrypted file from the filesystem and create a new file at the same path with .enc stripped from the filename $decryptedFile = $service->decryptFile($encryptedFile);