在我正在编写的PHP应用程序中,我不想向其他开发人员公开生产数据库凭据。
我在SO上读到了几个问题和答案,例如,下面的帖子对这个话题有很多有趣的想法:
如何在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对象,而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->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所指出的,应用程序的代码当然仍然可以获得文件的内容,从而访问凭据,因此我的整个推理是不正确的,因为它没有考虑这个非常简单的情况。我想我必须找到另一种策略,如果存在的话。。。
您可以组合两种策略:
1.分离开发和生产环境
最简单的方法是让它们"包括"数据库的位置、使用的帐户和配置文件中的密码,这在生产和开发方面是不同的。
->这样,开发人员就根本不了解生产方面的敏感部分。
2.为用户提供个人帐户
在开发数据库服务器上为您的开发人员提供单独的帐户,这样他们就可以获得他们可以做任何事情的(单独的)数据库,而您仍然可以拥有测试环境,在这些环境中,可以使用更像生产数据库的数据库来进行集成(因此可以更好地控制他们可能发生的事情)
这需要对每一位新招聘的开发人员进行一点用户管理,并在他们离开时采取一些行动,但让您的内部it支持人员在他们的清单上再添加一项,以及创建/删除电子邮件地址等,并不是很难。
如果在开发方面,你给他们单独的配置文件,让他们包括在内,所有这些文件最终都准备好投入生产,那么效果最好。
->这为开发人员提供了一个区域,他们可以在不影响彼此的情况下为所欲为,一旦他们离开,你就可以将其全部存档并离线。
如果您有开发服务器和生产服务器,那么您的开发人员不需要知道生产数据库的密码。如果你的开发人员直接在生产服务器上工作,那么你真的没有办法防止你的问题。通常只有sysadmin/devops知道DB密码,并在生产服务器中进行设置。您的开发人员应该有0访问权限。
最常见的解决方案是使用.env
文件来存储代码库所需的凭据。
开发人员获得(/make/custome)具有开发凭据的.env
文件,生产凭据仅在生产环境中可用。
这个.env
文件保存在文档根目录中,但没有随代码一起分发:它没有添加到存储库(git/svn)中
通常,.env.example
文件包含基本开发变量,例如外部API的测试环境路径和本地数据库的示例数据库凭据。与.env
不同,.env.example
被添加到源代码管理存储库中。
在代码方面,可以使用诸如dotenv之类的库来读取.env
文件的值。
假设你想保护自己免受恶意开发人员的后门攻击,你可以使用代码审查来防止这种尝试。在现代软件生产公司以及开源项目中,标准做法是只允许经过审查的代码合并到主分支中。
代码审查还有许多其他好处:对代码的每一部分都有额外的关注,可以防止错误,并鼓励开发人员相互学习。
当您遵循这样的协议时,单个开发人员几乎不可能访问生产凭据。