【问题标题】:How not to expose production DB credentials to other developers?如何不向其他开发人员公开生产数据库凭据?
【发布时间】:2018-11-22 17:29:48
【问题描述】:

在我正在编写的 PHP 应用程序中,我不想将生产数据库凭据暴露给其他开发人员。

我在这里阅读了几个关于 SO 的问题和答案,例如以下线程对该主题有许多有趣的想法:

How to secure database passwords in PHP?

我决定将凭据移到应用程序根目录之外的文件中。 假设我正在使用 PDO,并且在我的应用程序容器中创建了我的 PDO 实例:

<?php

// ...
require_once __DIR__ . '/../db_pdo_outside_document_root.php';

$containerConfig = [
   'db_connection' => function() {
      return new PDO(DB_PDO_DSN, DB_PDO_USER, DB_PDO_PASSWD, DB_PDO_OPTIONS);
   }
];
$appContainer = new ApplicationContainer($containerConfig);

// Use the container and handle the request...

传递给 PDO 构造函数的DB_PDO_* 常量都来自文档根目录之外的文件db_pdo_outside_document_root.php:

<?php
// db_pdo_outside_document_root.php
define('DB_PDO_DSN', 'mysql:host=localhost;dbname=app_database');
define('DB_PDO_USER', 'db_user');
define('DB_PDO_PASSWD', 'db_fancy_passwd');
define('DB_PDO_OPTIONS', [
    PDO::ATTR_PERSISTENT => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);

到目前为止,一切都很好。然而,这并没有多大帮助,因为如果有人想回显常量的内容,他们可以轻松做到:

<?php

// In some PHP file used by the application... 

echo DB_PDO_PASSWD; // echoes the DB password.
//mail('developer@mail.com', 'Subject', DB_PDO_PASSWD); // Or send it by email

现在,当然,您必须信任与您共事的同事,但谁知道呢,有时会发生员工离职、可能被解雇等情况。而且我们不希望他们有机会以某种方式将生产数据库凭据存储在他们的计算机上。

所以我想也许不是在文件中定义常量,而是文件本身可以返回 PDO 对象,这反过来似乎不会暴露它用来连接数据库的凭据:

<?php

// ...

var_dump($appContainer->get('db_connection'))

输出类似:

/path/to/htdocs/file.php:4:
object(PDO)[13]

所以我最终会在我的应用程序的引导代码中得到类似的东西:

<?php

// ...    

$containerConfig = [
   'db_connection' => function() {
      return require_once __DIR__ . '/../db_pdo_outside_document_root.php';
   }
];
$appContainer = new ApplicationContainer($containerConfig);

// Use the container and handle the request...

在外部文件中:

<?php
// db_pdo_outside_document_root.php
return new PDO('mysql:host=localhost;dbname=app_database', 
'db_user', 'db_fancy_passwd', [
    PDO::ATTR_PERSISTENT => false,
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
]);;

但我不知道这是否足够,或者是否有一些我应该注意的警告(除了这个“解决方法”有点丑陋的事实)。

你认为其他开发人员能够以某种方式从$appContainer-&gt;get('db_connection') 的返回值中读取凭据吗(假设它返回上面的 PDO 对象)?

我也尝试了ReflectionClass,但我没有看到该对象的任何属性:

<?php

//...

$ref = new ReflectionClass($appContainer->get('db_connection'));
var_dump($ref->getProperties());

输出:

/path/to/htdocs/file.php:4:
array (size=0)
  empty

您如何看待这种方法?不是本世纪的发明,但它似乎完成了这项工作。或者,也许还有一种方法可以访问我不知道的应用程序代码中的凭据。

我想听听你的意见。

感谢您的关注。

EDI:正如@IsThisJavascript 指出的那样,应用程序的代码当然仍然可以获取文件的内容并因此访问凭据,因此我的整个推理不正确,因为它没有考虑这种非常简单的情况。 我想我必须找到另一种策略,如果存在的话......

【问题讨论】:

  • maybe there is still a way to access the credentials in the application's code I am not aware of. 如果他们可以访问服务器,那么他们需要做的就是在__DIR__ . '/../db_pdo_outside_document_root.php'; 上使用file_get_contents
  • 应该考虑一下,好简单啊
  • 然后我可以拒绝所有以某种方式访问​​该文件的推送代码。这虽然不是微不足道的,似乎有点复杂
  • 也就是说,您应该设置一个不共享数据库凭据的登台服务器。然后你将负责推动一切生活。开发人员不需要在产品服务器上工作 - 随着代码库的增长,这会导致太多问题
  • +1 表示“开发人员永远不会接触生产”。开发人员喜欢在没有测试或文档的情况下说“我只是需要在 prod 中做这件事”之类的话,然后,即使它没有立即损坏,你也有这个地雷在等着你下次部署时踩到它。

标签: php security pdo web-applications


【解决方案1】:

您可以结合两种策略:

1.分离开发和生产环境

最简单的方法是让它们“包含”数据库的位置、使用的帐户以及配置文件中的密码,这在生产和开发方面是不同的。

-> 这样,开发人员根本不会了解生产方面的敏感信息。

2。为用户提供个人帐户

在您的开发数据库服务器上为您的开发人员提供个人帐户,以便他们获得可以处理所有事情的(个人)数据库,同时您仍然可以拥有可以使用更类似于生产环境的数据库进行集成的测试环境(以及因此可以更好地控制可能发生在他们身上的事情)

这需要对每个新招聘的开发人员进行一些用户管理,并在他们离开时采取一些行动,但是让您的内部 IT 支持人员在他们的清单上添加更多项目以及创建/删除电子邮件并不是那么困难地址等

如果在开发方面你给他们单独的配置文件包括在内,这一切都准备好最终进入生产阶段,这将是最好的。

-> 这为开发人员提供了一个区域,他们可以在其中做任何他们喜欢的事情,而不会相互影响,并且一旦他们离开,您就可以将其全部存档并离线。

【讨论】:

    【解决方案2】:

    如果您有开发服务器和生产服务器,您的开发人员不需要知道生产数据库的密码。如果您的开发人员直接在生产服务器上工作,那么您真的无法阻止您的问题。通常只有 sysadmin/devops 知道数据库密码,并且他在生产服务器中设置该密码。您的开发人员应该有 0 访问权限。

    【讨论】:

    • 但是我如何才能阻止他们添加代码行指出?我只能想到一个开发人员不知道并且他们无法以某种方式猜测的文件名。
    • @tonix 如果您的开发人员仅在开发服务器上工作,您(或您的系统管理员/开发人员)将有机会在将代码推送到生产之前检查代码是否有恶意。无论如何,这就是您应该做的,您的所有开发人员的工作都应该在推送到生产服务器之前进行审查/测试。
    • @tonix 在该级别无法信任您的开发人员是第 8 层问题,通常通过管理/人力资源政策和/或暴力威胁来解决。像那样特意闯入 prod 数据库是一种可激发的进攻。
    • 我知道,通常没有人会这样做。但是想想一家公司,其开发人员远程工作并分布在世界各地,现在你不能真正信任每个人
    • 也许 AOP 可以在这种情况下提供帮助?如果我在应用程序顶部注册 AOP 层,并且在调用每个函数之前检查其中一个参数是否是存储 PDO 实例创建的文件,我可以中断程序并出现异常。这样,应用程序甚至不会通过在部署代码之前执行测试的暂存阶段......但是我会猜到一个不小的开销,我不知道,我只是在考虑可能性.
    【解决方案3】:

    最常见的解决方案是使用.env 文件来存储代码库所需的凭据。

    开发人员获取 (/make/customise) 带有开发凭据的 .env 文件,生产凭据仅在生产环境中可用。

    这个.env 文件保存在文档根目录中,但不与代码一起分发:它没有添加到存储库(git/svn)

    通常,.env.example 文件包含在基本开发变量中,例如外部 API 测试环境的路径和本地数据库的示例数据库凭据。与.env 相比,.env.example 已添加到源代码控制存储库中。

    在代码方面,可以使用dotenv等库来读取.env文件的值。

    假设您希望保护自己免受恶意开发者的后门攻击,您可以使用代码审查来防止此类尝试。在现代软件生产公司以及开源项目中,标准做法是只允许将经过审查的代码合并到主分支中。

    代码审查还有许多其他好处:对代码的每个部分有额外的关注可以防止错误并鼓励开发人员相互学习。

    当您遵循这样的协议时,单个开发人员几乎不可能访问生产凭据。

    【讨论】:

    • .env 文件是纯文本。环境变量通常也是纯文本。这可能是一个常见的解决方案,但它不是一个安全的解决方案。
    • 当然是纯文本。服务器需要访问未加密的密码,因此即使您要加密生产 .env 文件(仅存在于生产服务器上,红色),您也需要将解密机制和密钥放在完全相同的位置,使它相当无用。比分发加密凭据更安全的是,根本不将凭据分发给不需要它的人。因此采用了这种方法。
    猜你喜欢
    • 2013-01-15
    • 1970-01-01
    • 2013-12-31
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    • 2012-01-03
    • 2012-04-15
    • 1970-01-01
    相关资源
    最近更新 更多