【问题标题】:Automatically replace user passwords in mysql db dump on server side (Laravel)自动替换服务器端 mysql db dump 中的用户密码(Laravel)
【发布时间】:2017-05-18 20:43:22
【问题描述】:

用例

要设置开发环境,需要一个应用程序数据库的 mysql 转储。转储源是生产数据库。

问题

我不想将转储提供给任何人,因为它包含(散列的)用户密码。

解决方案构思

在授予对转储的访问权限之前,在服务器端替换所有用户密码(用于开发目的的所有用户一个密码就可以了)。

环境

  • Laravel 应用程序
  • MySQL 数据库
  • bash 脚本可以在 Capistrano 上运行或通过 ssh 在服务器上手动执行

任何想法如何以聪明的方式解决这个问题?

示例转储(仅 users 表)

# ************************************************************
# Sequel Pro SQL dump
# Version 4541
#
# http://www.sequelpro.com/
# https://github.com/sequelpro/sequelpro
#
# Host: 127.0.0.1 (MySQL 5.7.12)
# Datenbank: app
# Erstellt am: 2017-01-04 14:22:35 +0000
# ************************************************************


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;


# Export von Tabelle users
# ------------------------------------------------------------

DROP TABLE IF EXISTS `users`;

CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `role` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `tenant_id` int(10) unsigned DEFAULT NULL,
  `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(60) COLLATE utf8_unicode_ci NOT NULL,
  `remember_token` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL,
  `created_at` timestamp NULL DEFAULT NULL,
  `updated_at` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `users_email_tenant_id_role_unique` (`email`,`tenant_id`,`role`),
  KEY `users_tenant_id_index` (`tenant_id`),
  CONSTRAINT `users_tenant_id_foreign` FOREIGN KEY (`tenant_id`) REFERENCES `tenants` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

LOCK TABLES `users` WRITE;
/*!40000 ALTER TABLE `users` DISABLE KEYS */;

INSERT INTO `users` (`id`, `role`, `tenant_id`, `name`, `email`, `password`, `remember_token`, `created_at`, `updated_at`)
VALUES
    (1,'admin',1,'appadmin','admin@example.com','123$15$g4qKHcS7zHercuNJobfFxOTWGoW7YN.tphFdddGIIEXkrkE8Etxxx',NULL,'2017-01-04 14:19:04','2017-01-04 14:19:04');

/*!40000 ALTER TABLE `users` ENABLE KEYS */;
UNLOCK TABLES;

/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

【问题讨论】:

  • 请在您的问题中添加示例转储(用相同数量的随机字符替换散列密码)以及该示例转储所需的输出。
  • 最简单的方法是将数据库加载到本地服务器,更新密码,创建第二个转储。
  • @Cyrus 我添加了一个示例转储(仅数据库的用户表)
  • @VasilShaddix 我正在寻找自动化解决方案……
  • 您可以控制流程的哪一部分?我的意思是,你有能力改变哪些部分?你能规定什么被倾倒在首位吗?或者,您是否遇到了文本转储,需要清理该文件?另外:您使用的是什么操作系统?是否只需要使用 bash 完成?我们在谈论多少条记录?

标签: php mysql bash laravel laravel-5


【解决方案1】:
  1. 使用 mysqldump 选项
    mysqldump -d app - 转储所有数据
    mysqldump -t --ignore-table=app.users app - 仅转储数据但排除用户表

  2. 在转储文件中搜索密码模式并将其替换,例如使用 linux sed:
    sed -i 's/'\''\$2y\$[0-9]\{2\}\$.\{53\}'\''/'\''new-hash-here'\''/g' dump.sql

【讨论】:

    【解决方案2】:

    我不熟悉控制台环境正则表达式。但是最好转储数据,然后做一些事情

    (^\s*\([0-9]+,'.*',[0-9]+,'.*','.*',)'.*'(,.*,.*,.*\))
    

    替换为

    \1'NEW_HASH'\2
    

    【讨论】:

      【解决方案3】:

      这是一个使用strike 的解决方案,它是my_obfuscate 的命令行脚本包装器,它是一个专为混淆SQL 转储而设计的库。

      首先,安装strike 实用程序(需要在系统上安装ruby):

      gem install strike
      

      接下来,运行 strike obfuscate 来混淆您的转储。以下示例将users 表中的所有password 值替换为固定字符串"password":

      strike obfuscate \
        -p <(echo 'table(:users){|t| t.password type: :fixed, string: "password"}') \
        < dump.sql
      

      注意:由于该库执行逐行解析,因此仅当INSERT INTOusers() VALUES () 命令位于一行时才有效,如下所示:

       INSERT INTO `users` (`id`, `role`, `tenant_id`, `name`, `email`, `password`, `remember_token`, `created_at`, `updated_at`) VALUES (1,'admin',1,'appadmin','admin@example.com','123$15$g4qKHcS7zHercuNJobfFxOTWGoW7YN.tphFdddGIIEXkrkE8Etxxx',NULL,'2017-01-04 14:19:04','2017-01-04 14:19:04');
      

      strike obfuscate 命令的输出将返回整个 SQL 转储内容,但修改 INSERT 行以使 password 值混淆:

      INSERT INTO `users` (`id`, `role`, `tenant_id`, `name`, `email`, `password`, `remember_token`, `created_at`, `updated_at`) VALUES ('1','admin','1','appadmin','admin@example.com','password',NULL,'2017-01-04 14:19:04','2017-01-04 14:19:04');
      

      【讨论】:

        【解决方案4】:

        创建一个简单的命令来替换用户表中的所有(非管理员)电子邮件地址和密码,然后转储数据库。下面的密码保护命令会更改所有不使用给定域的电子邮件地址,然后更改所有帐户的密码。在fire 方法的末尾,添加您的工匠命令以转储数据库。 (假设你已经有一个包)。

        class RelacePasswordsAndEmailsCommand extends Command {
            protected $name = 'mycommand/safe_user_dump';
            protected $description = 'Changes all email addresses and passwords for a safe dump';
            public function __construct() {
                parent::__construct();
            }
        
            public function fire() {
                if ($this->confirm('WARNING! This will change all email addresses and passwords in the database. Do you wish to continue? [yes|no]')) {
                    $password = $this->secret('What is the password?');
                    if ( $password === 'mysecretpassword' ) {
                        $emails = DB::table('users')
                            ->where(function ($q) {
                                return $q->where('email', 'NOT LIKE', '%@example.com');
                            })->lists('id');
                        foreach ($emails as $id ) {
                            DB::table('users')->where('id', $id)->update(['email' => 'user' . $id . '@example.com']);
                        }
                        DB::table('users')->update(['password' => 'myhashpassword'])
        
                        $this->info( count($emails) . ' email addresses and passwords changed.');
        
                        # Add your database dump command here
        
                    } else {
                        $this->info('The password was incorrect.');
                    }
                }
            }
        
        }
        

        【讨论】:

        • 这会覆盖生产数据,你错过了一个中间步骤,或者?
        • 对不起,我应该提到你应该在将数据库复制到登台服务器后运行它。
        【解决方案5】:

        我建议使用 sql 方式:

        create table users_tmp like users;
        insert into users_tmp select * from users;
        update users_tmp set password='whatever';
        

        然后在导入之后

        rename table users_tmp to users;
        

        【讨论】:

          【解决方案6】:

          用例:

          • 您可以转储生产数据库,将数据库导入测试/阶段环境并更新用户表。 用于用户匿名化的 SQL:

            UPDATE User
            SET
              mobile_phone  = NULL,
              private_phone = NULL,
              email = IF(isnull(email), NULL, concat('user', id, '@test.local')),
              password = MD5('code')
            ;
            
          • 开发人员应该只从测试/阶段环境中转储数据库。

          【讨论】:

            【解决方案7】:

            要以智能的方式解决这个问题,不要转储数据库。

            要获得更好的可行开发环境,您最好:

            • 使用模式转储(例如:mysqldump --no-data)或模式数据库迁移(我相信 laravel 有内置的)或模式规范(如果你使用例如:Propel)创建您的表格
            • 使用固定装置和/或控制台命令来填充数据库,以完成任何不特殊的开发任务(付款或其他古怪的东西)所需的任何内容
            • 使用容器化工具,例如 docker 和/或 vagrant(我同时使用)
            • 也许您可以将所有开发环境配置详细信息保留在主存储库中,除非您为配置创建一个特殊存储库
            • 也许为自己创建一个构建/清理/重建开发环境的脚本

            这将为您带来很多好处(例如:您可以在开发人员文档中添加测试用户凭据,以及预先填充其他数据,如角色和其他数据)。

            您可以以快速方式使用此处在其他答案中介绍的其他几个解决方案。

            【讨论】:

            • 我完全同意你的看法,这是最好的解决方案,我们有迁移来轻松地重新创建架构,但现在没有完成的数据库播种机,这就是我寻找替代方案的原因(即使用生产转储)
            • 为什么不创建自己的播种机?您可以创建一个为 vanilla 数据库播种的 CLI 命令。我已经为几个项目做到了这一点,我通常在配置结束时运行该命令。您可以将其添加到开发人员特定的子命名空间(例如:App\Console\Commands\Dev)。 Artisan 基于 symfony 控制台,添加了一些糖,所以应该很容易。
            猜你喜欢
            • 2011-08-19
            • 2012-01-11
            • 2011-05-24
            • 2018-08-02
            • 1970-01-01
            • 1970-01-01
            • 2021-06-04
            • 1970-01-01
            • 2011-05-27
            相关资源
            最近更新 更多