加密服务
重要
不要使用此或任何其他加密库来存储密码!密码必须哈希,您应该通过 PHP 的 密码哈希扩展 来执行此操作。
加密服务提供双向对称(密钥)数据加密。该服务将实例化和/或初始化一个加密处理程序以适合您的参数,如下所述。
加密服务处理程序必须实现 CodeIgniter 的简单 EncrypterInterface
。使用适当的 PHP 密码扩展或第三方库可能需要在您的服务器上安装额外的软件,或者可能需要在您的 PHP 实例中显式启用。
目前支持以下 PHP 扩展
这不是一个完整的加密解决方案。如果您需要更多功能,例如公钥加密,建议您考虑直接使用 OpenSSL 或其他加密扩展。一个更全面的软件包,例如Halite(一个基于 libsodium 的 O-O 软件包)是另一种选择。
注意
对 MCrypt
扩展的支持已被删除,因为它已在 PHP 7.2 中弃用。
使用加密库
与 CodeIgniter 中的所有服务一样,它可以通过 Config\Services
加载。
<?php
$encrypter = \Config\Services::encrypter();
假设您已设置初始密钥(请参阅配置库),加密和解密数据很简单 - 将相应的字符串传递给 encrypt()
和/或 decrypt()
方法。
<?php
$plainText = 'This is a plain-text message!';
$ciphertext = $encrypter->encrypt($plainText);
// Outputs: This is a plain-text message!
echo $encrypter->decrypt($ciphertext);
就是这样!加密库将完成整个过程所需的全部操作,使其开箱即用地具有加密安全性。您无需担心它。
配置库
上面的示例使用的是在 app/Config/Encryption.php 中找到的配置设置。
选项 |
可能的值(括号内为默认值) |
---|---|
key |
加密密钥启动器 |
driver |
首选处理程序,例如 OpenSSL 或 Sodium ( |
digest |
消息摘要算法 ( |
blockSize |
[SodiumHandler 仅限] 填充长度(字节)( |
cipher |
[OpenSSLHandler 仅限] 要使用的密码( |
encryptKeyInfo |
[OpenSSLHandler 仅限] 加密密钥信息( |
authKeyInfo |
[OpenSSLHandler 仅限] 身份验证密钥信息( |
rawData |
[OpenSSLHandler 仅限] 密文是否应为原始数据( |
您可以通过将您自己的配置对象传递给 Services
调用来替换配置文件的设置。 $config
变量必须是 Config\Encryption
类的实例。
<?php
$config = new \Config\Encryption();
$config->key = 'aBigsecret_ofAtleast32Characters';
$config->driver = 'OpenSSL';
$encrypter = \Config\Services::encrypter($config);
保持与 CI3 兼容性的配置
版本 4.3.0 中新增。
从 v4.3.0 开始,您可以解密使用 CI3 的 Encryption 加密的數據。如果您需要解密此类数据,请使用以下设置以保持兼容性。
<?php
use Config\Encryption;
use Config\Services;
$config = new Encryption();
$config->driver = 'OpenSSL';
// Your CI3's 'encryption_key'
$config->key = hex2bin('64c70b0b8d45b80b9eba60b8b3c8a34d0193223d20fea46f8644b848bf7ce67f');
// Your CI3's 'cipher' and 'mode'
$config->cipher = 'AES-128-CBC';
$config->rawData = false;
$config->encryptKeyInfo = 'encryption';
$config->authKeyInfo = 'authentication';
$encrypter = Services::encrypter($config, false);
支持的 HMAC 身份验证算法
对于 HMAC 消息身份验证,Encryption 库支持使用 SHA-2 算法系列
算法 |
原始长度(字节) |
十六进制编码长度(字节) |
---|---|---|
SHA512 |
64 |
128 |
SHA384 |
48 |
96 |
SHA256 |
32 |
64 |
SHA224 |
28 |
56 |
不包含其他流行算法(如 MD5 或 SHA1)的原因是,它们不再被认为足够安全,因此我们不想鼓励使用它们。如果您绝对需要使用它们,可以通过 PHP 的原生 hash_hmac() 函数轻松实现。
当然,将来会随着更强大的算法出现并广泛可用而添加。
默认行为
默认情况下,Encryption 库使用 OpenSSL 处理程序。该处理程序使用 AES-256-CTR 算法、您配置的密钥和 SHA512 HMAC 身份验证进行加密。
设置您的加密密钥
您的加密密钥必须与所用加密算法允许的长度一样长。对于 AES-256,长度为 256 位或 32 字节(字符)。
密钥应该尽可能随机,并且**不能**是常规的文本字符串,也不能是哈希函数的输出等。要创建合适的密钥,可以使用加密库的createKey()
方法。
<?php
// $key will be assigned a 32-byte (256-bit) random key
$key = \CodeIgniter\Encryption\Encryption::createKey();
// for the SodiumHandler, you can use either:
$key = sodium_crypto_secretbox_keygen();
$key = \CodeIgniter\Encryption\Encryption::createKey(SODIUM_CRYPTO_SECRETBOX_KEYBYTES);
密钥可以存储在**app/Config/Encryption.php**中,或者您可以设计自己的存储机制,并在加密/解密时动态传递密钥。
要将密钥保存到您的**app/Config/Encryption.php**中,请打开该文件并设置
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Encryption extends BaseConfig
{
public $key = 'YOUR KEY';
// ...
}
编码密钥或结果
您会注意到createKey()
方法输出二进制数据,这很难处理(例如,复制粘贴可能会损坏它),因此您可以使用bin2hex()
或base64_encode
以更友好的方式处理密钥。例如
<?php
// Get a hex-encoded representation of the key:
$encoded = bin2hex(\CodeIgniter\Encryption\Encryption::createKey(32));
// Put the same value with hex2bin(),
// so that it is still passed as binary to the library:
$key = hex2bin('your-hex-encoded-key');
您可能会发现相同的技术对加密结果也很有用
<?php
// Encrypt some text & make the results text
$encoded = base64_encode($encrypter->encrypt($plaintext));
在存储密钥时使用前缀
您可以在存储加密密钥时利用两个特殊前缀:hex2bin:
和base64:
。当这些前缀紧接在密钥的值之前时,Encryption
将智能地解析密钥,并将二进制字符串传递给库。
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class Encryption extends BaseConfig
{
// In Encryption, you may use
public $key = 'hex2bin:<your-hex-encoded-key>';
// or
public $key = 'base64:<your-base64-encoded-key>';
// ...
}
同样,您也可以在您的**.env**文件中使用这些前缀!
// For hex2bin
encryption.key = hex2bin:<your-hex-encoded-key>
// or
encryption.key = base64:<your-base64-encoded-key>
填充
有时,消息的长度可能会提供很多关于其性质的信息。如果消息是“是”、“否”和“也许”之一,加密消息没有帮助:知道长度就足以知道消息是什么。
填充是一种通过使长度成为给定块大小的倍数来缓解这种情况的技术。
填充在 SodiumHandler
中使用 libsodium 的原生 sodium_pad
和 sodium_unpad
函数实现。这需要使用填充长度(以字节为单位),该长度在加密之前添加到明文消息中,并在解密后删除。填充可以通过 Config\Encryption
的 $blockSize
属性进行配置。此值应大于零。
重要
建议不要自行设计填充实现。您必须始终使用库中更安全的实现。此外,密码不应该被填充。不建议使用填充来隐藏密码的长度。愿意将密码发送到服务器的客户端应该对其进行哈希处理(即使只使用哈希函数的一次迭代)。这确保了传输数据的长度是恒定的,并且服务器不会轻易获得密码的副本。
加密处理程序说明
OpenSSL 说明
OpenSSL 扩展已成为 PHP 的标准部分很长时间了。
CodeIgniter 的 OpenSSL 处理程序使用 AES-256-CTR 密码。
您的配置提供的 *密钥* 用于推导出另外两个密钥,一个用于加密,另一个用于身份验证。这是通过一种称为 基于HMAC的密钥派生函数 (HKDF) 的技术实现的。
Sodium 说明
Sodium 扩展从 PHP 7.2.0 开始默认捆绑在 PHP 中。
Sodium 使用 XSalsa20 算法进行加密,Poly1305 用于 MAC,XS25519 用于密钥交换,以在端到端场景中发送秘密消息。为了使用共享密钥(例如对称加密)加密和/或验证字符串,Sodium 使用 XSalsa20 算法进行加密,并使用 HMAC-SHA512 进行身份验证。
注意
CodeIgniter 的 SodiumHandler
在每次加密或解密会话中使用 sodium_memzero
。在每次会话之后,消息(无论是明文还是密文)和起始密钥都会从缓冲区中清除。您可能需要在开始新会话之前再次提供密钥。
消息长度
加密后的字符串通常比原始的明文字符串更长(取决于密码)。
这受密码算法本身、附加到密文的初始化向量 (IV) 以及也附加的 HMAC 身份验证消息的影响。此外,加密后的消息也进行了 Base64 编码,以便无论使用何种字符集,它都可以安全地存储和传输。
在选择数据存储机制时请牢记这些信息。例如,Cookie 只能保存 4K 的信息。
直接使用加密服务
除了(或除了)使用 Services
(如 使用加密库 中所述),您还可以直接创建一个“Encrypter”,或更改现有实例的设置。
<?php
// create an Encryption instance
$encryption = new \CodeIgniter\Encryption\Encryption();
// reconfigure an instance with different settings
$encrypter = $encryption->initialize($config);
请记住,$config
必须是 Config\Encryption
类的实例。
类参考
- class CodeIgniter\Encryption\Encryption
- static createKey([$length = 32])
- 参数:
$length (
int
) – 输出长度
- 返回值:
一个具有指定长度的伪随机加密密钥,或在失败时返回
false
- 返回类型:
string
通过从操作系统源(例如
/dev/urandom
)获取随机数据来创建加密密钥。
- initialize([Encryption $config = null])
- 参数:
$config (
Config\Encryption
) – 配置参数
- 返回值:
CodeIgniter\Encryption\EncrypterInterface
实例- 返回类型:
CodeIgniter\Encryption\EncrypterInterface
- 抛出:
CodeIgniter\Encryption\Exceptions\EncryptionException
初始化(配置)库以使用不同的设置。
示例
<?php $encrypter = $encryption->initialize(['cipher' => 'AES-256-CTR']);
请参考 配置库 部分以获取详细的信息。
- CodeIgniter\Encryption\EncrypterInterface
- encrypt($data[, $params = null])
- 参数:
$data (
string
) – 要加密的数据$params (
array|string|null
) – 配置参数(密钥)
- 返回值:
加密后的数据
- 返回类型:
string
- 抛出:
CodeIgniter\Encryption\Exceptions\EncryptionException
加密输入数据并返回其密文。
如果您将参数作为第二个参数传递,则
key
元素将用作此操作的起始密钥,如果$params
是一个数组;或者起始密钥可以作为字符串传递。如果您使用的是 SodiumHandler 并且想要在运行时传递不同的
blockSize
,请在$params
数组中传递blockSize
密钥。示例
<?php $ciphertext = $encrypter->encrypt('My secret message'); $ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key']); $ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key', 'blockSize' => 32]); $ciphertext = $encrypter->encrypt('My secret message', 'New secret key'); $ciphertext = $encrypter->encrypt('My secret message', ['blockSize' => 32]);
- decrypt($data[, $params = null])
- 参数:
$data (
string
) – 要解密的数据$params (
array|string|null
) – 配置参数(密钥)
- 返回值:
解密后的数据
- 返回类型:
string
- 抛出:
CodeIgniter\Encryption\Exceptions\EncryptionException
解密输入数据并以明文形式返回。
如果您将参数作为第二个参数传递,则
key
元素将用作此操作的起始密钥,如果$params
是一个数组;或者起始密钥可以作为字符串传递。如果您使用的是 SodiumHandler 并且想要在运行时传递不同的
blockSize
,请在$params
数组中传递blockSize
密钥。示例
<?php echo $encrypter->decrypt($ciphertext); echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key']); echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key', 'blockSize' => 32]); echo $encrypter->decrypt($ciphertext, 'New secret key'); echo $encrypter->decrypt($ciphertext, ['blockSize' => 32]);