加密和解密数据

Yii2框架包含了一个特殊的安全组件,它提供了一套方法来处理常见的安全相关的任务。\yii\base\Security类需要OpenSSLPHP扩展,而不是mcrypt

准备

  1. 按照官方指南http://www.yiiframework.com/doc-2.0/guide-start-installation.html的描述,使用Composer包管理器创建一个新的应用。
  2. 设置数据库连接,并创建一个名叫order的表,如下所示:
  1. DROP TABLE IF EXISTS `order`;
  2. CREATE TABLE IF NOT EXISTS `order` (
  3. `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  4. `client` VARCHAR(255) NOT NULL,
  5. `total` FLOAT NOT NULL,
  6. `encrypted_field` BLOB NOT NULL,
  7. PRIMARY KEY (`id`)
  8. );
  1. 使用Gii生成Order模型。

如何做…

  1. 添加一个额外的key参数到config/params.php
  1. <?php
  2. return [
  3. 'adminEmail' => 'admin@example.com',
  4. 'key' => 'mysecretkey'
  5. ];
  1. Order模型添加behaviorshelper属性:
  1. public $encrypted_field_temp;
  2. public function behaviors()
  3. {
  4. return [
  5. [
  6. 'class' => AttributeBehavior::className(),
  7. 'attributes' => [
  8. ActiveRecord::EVENT_BEFORE_INSERT => 'encrypted_field',
  9. ActiveRecord::EVENT_BEFORE_UPDATE => 'encrypted_field',
  10. ],
  11. 'value' => function ($event) {
  12. $event->sender->encrypted_field_temp = $event->sender->encrypted_field;
  13. return Yii::$app->security->encryptByKey(
  14. $event->sender->encrypted_field,
  15. Yii::$app->params['key']
  16. );
  17. },
  18. ],
  19. [
  20. 'class' => AttributeBehavior::className(),
  21. 'attributes' => [
  22. ActiveRecord::EVENT_AFTER_INSERT => 'encrypted_field',
  23. ActiveRecord::EVENT_AFTER_UPDATE => 'encrypted_field',
  24. ],
  25. 'value' => function ($event) {
  26. return $event->sender->encrypted_field_temp;
  27. },
  28. ],
  29. [
  30. 'class' => AttributeBehavior::className(),
  31. 'attributes' => [
  32. ActiveRecord::EVENT_AFTER_FIND => 'encrypted_field',
  33. ],
  34. 'value' => function ($event) {
  35. return Yii::$app->security->decryptByKey(
  36. $event->sender->encrypted_field,
  37. Yii::$app->params['key']
  38. );
  39. },
  40. ],
  41. ];
  42. }
  1. 添加controller/CryptoController.php
  1. <?php
  2. namespace app\controllers;
  3. use app\models\Order;
  4. use Yii;
  5. use yii\db\Query;
  6. use yii\helpers\ArrayHelper;
  7. use yii\helpers\Html;
  8. use yii\helpers\VarDumper;
  9. use yii\web\Controller;
  10. /**
  11. * Class CryptoController.
  12. * @package app\controllers
  13. */
  14. class CryptoController extends Controller
  15. {
  16. public function actionTest()
  17. {
  18. $newOrder = new Order();
  19. $newOrder->client = "Alex";
  20. $newOrder->total = 100;
  21. $newOrder->encrypted_field = 'very-secret-info';
  22. $newOrder->save();
  23. $findOrder = Order::findOne($newOrder->id);
  24. return $this->renderContent(Html::ul([
  25. 'New model: ' . VarDumper::dumpAsString($newOrder->attributes),
  26. 'Find model: ' . VarDumper::dumpAsString($findOrder->attributes)
  27. ]));
  28. }
  29. public function actionRaw()
  30. {
  31. $row = (new Query())->from('order')
  32. ->where(['client' => 'Alex'])
  33. ->one();
  34. return $this->renderContent(Html::ul(
  35. $row
  36. ));
  37. }
  38. }
  1. 运行crypto/test

加密和解密数据 - 图1

  1. 为了查看原始数据,运行crypto/raw

加密和解密数据 - 图2

工作原理…

首先,我们已经添加了AttributeBehavior,当特定事件发生时,它会自动处理我们的数据。我们特定的事件是ActiveRecord::EVENT_AFTER_INSERTActiveRecord::EVENT_AFTER_UPDATEActiveRecord::EVENT_AFTER_FIND

在插入和更新事件期间,我们使用了一个特殊的方法Yii::$app->security->encryptByKey();加密了我们的数据。在保存到数据库前,这个方法使用HKDF和一个随机盐来加密我们的数据。从数据库中获取数据以后,我们也可以使用ActiveRecord::EVENT_AFTER_FIND方法来解密我们的数据。在这个例子中,我们也使用了特殊的Yii2方法Yii::$app->security->encryptByKey();。这个方法接受两个参数:加密的数据和key。

更多…

除了数据加密和解密以外,一个安全的组件也提供了基于标准算法的key derivation、数据防破坏和密码校验。

使用密码

校验一个密码:

  1. if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
  2. // all good, logging user in
  3. } else {
  4. // wrong password
  5. }

参考

为了了解更多关于SQL注入和使用Yii处理数据库的知识,参考http://www.yiiframework.com/doc-2.0/guide-security-passwords.html