116

我有一个在MySQL数据库中存储数据的小型 PHP 应用程序。目前用户名/密码在 PHP 代码中是硬编码的。例如,我不太喜欢这种情况,因为代码也可以在存储库中使用。

我最好的想法是将数据从代码移动到配置文件(从存储库中排除),并以某种方式对其进行编码,因此不能直接读取(混淆)。有没有更好更容易使用的方法来解决这个问题?

$link = mysql_connect('localhost', 'mysql_user', 'mysql_password');
if (!$link) { 
    die('Could not connect: ' . mysql_error());
}
mysql_select_db('mydb');

范围:我想建立一个强大且易于使用的解决方案。我想要合理的安全性,但我不是在这里处理高度机密的数据。

备注:不再推荐使用mysql_connect函数,见 Stack Overflow 问题为什么我不应该在 PHP 中使用 mysql_ 函数?*。我本可以更改代码示例,但由于一些评论提到了这个,我没有。但是,问题的原始性质仍然有效。

4

9 回答 9

69

正如您所说,最简单的方法是使用配置文件。

许多框架都使用它(ZendCakePHPKohana等),它是最常见的做事方式(即使在非 PHP 环境中,例如带有web.config文件的 ASP.NET)。这使您还可以通过仅复制站点的文件来将配置值从一个环境复制到另一个环境,这比依赖于服务器设置环境变量(可能很快丢失和忘记)有好处。

您不必担心密码的混淆,因为它不是一个世界可访问的文件,它当然不应该是网络可访问的。我的意思是,您要么 a) 告诉您的 Web 服务器不要提供您的配置文件(IIS已经使用web.config文件执行此操作并提供 HTTP 404.8 状态而不是内容)或 b) 将其移到您的 Web 服务之外目录。如果有人可以看到您的配置文件,那比在您的源代码中拥有它更糟糕。

拥有配置文件的基本(空/默认)版本也是一个好主意,并将其按环境分开,这样您就可以为生产、开发和测试平台提供不同的配置文件。

环境变量是区分这些环境的最常用方法,类似于以下代码:

// Check if it's been set by the web server
if (!empty($_ENV['ENVIRONMENT'])) {
    // Copy from web server to PHP constant
    define('ENVIRONMENT', $_ENV['ENVIRONMENT']);
}

if (!defined('ENVIRONMENT')) {
    // Default to development
    define('ENVIRONMENT', 'development');
}

// Load in default configuration values
require_once 'config.default.php';

// Load in the overridden configuration file for this environment
require_once 'config.' . ENVIRONMENT . '.php';

另一种非常常见的方法是使用 XML 配置文件,并且只读取您需要的值(将配置文件的缓存副本存储在内存中)。这可以很容易地限制为仅加载某些值,而不是允许任意包含 PHP 文件,并且在我看来总体上是一个更好的解决方案,但上述内容应该让您朝着正确的方向开始。

您可能希望您的VCS忽略该文件。另一方面,您可能希望文件的骨架或具有合理默认值的骨架(后者当然不适用于登录数据)进行版本控制。处理这个问题的一种常见方法是拥有一个签入的模板配置文件,安装过程将该文件复制到实际配置文件的位置,在那里进行定制。这可以是手动或自动化的过程。

(虽然与主要问题有些无关,但为您的环境引入一个常量可以让您做一些其他很酷的事情,例如推迟到假邮件实现而不是实时SMTP实现,但当然这也可以通过配置文件完成)

于 2013-02-26T12:22:21.677 回答
47

一个非常好的解决方案,如果您使用的是 Apache,它将信息存储在虚拟主机配置中

SetEnv  MYSQL_USER     "xx"
SetEnv  MYSQL_PASSWORD "y2wrg435yw8"

可以轻松获取数据以$_ENV[]用于代码中。

于 2013-02-26T12:24:11.997 回答
11

正如其他人所提到的,将它放在源代码控制之外的单独配置文件中(显然这将在源代码控制下的代码中提到)。

将文件命名为config.php而不是config.ini也是一个好主意,以防目录被意外暴露,这意味着文件不会被下载,而是什么也不返回。

于 2013-02-26T12:33:37.623 回答
6

如果您觉得12factor方式很有价值,他们建议将配置存储在环境中。

这具有额外的优势,即允许您在测试时或在非生产环境中编写完全相同的代码。如果您想(或需要)更改数据库或其他任何内容,则无需修改代码 - 您只需更改环境变量即可。

于 2013-02-26T15:44:24.323 回答
2

我要做的是仅将示例配置文件存储在存储库中,例如 config.php.dist 并且不要将实际的 config.php 置于版本控制之下。

于 2013-02-26T12:21:32.790 回答
2

将密码从代码移动到配置文件是个好主意,这样密码就不会出现在存储库中。在配置文件中加密它的想法是有问题的,因为拥有配置文件 + 解密它的 PHP 代码的人总是可以运行代码并获得明文密码。可能最好将配置文件中的密码保存为纯文本,并考虑如何保护配置文件免受未经授权的访问。

于 2013-02-26T12:25:17.263 回答
2

好问题。您可以将最敏感的部分(例如密钥/密码)作为环境变量移出,但这只会将问题推迟到您的服务器配置(大概也在存储库中)。

您还可以尝试避免对数据库等内容使用密码,方法是减少密码并将其保护在防火墙后面。这些都不是完美的解决方案,但它们是我所知道的方法。

于 2013-02-26T12:26:17.047 回答
1

您始终可以使用函数parse_ini_file创建配置 ini 文件。

于 2013-02-26T12:25:38.767 回答
1

我在这里看不到所有这些问题。如果您正在共享存储库,您可能不想硬编码密码和配置。您应该改为提供默认值:

host: localhost
user: root
pass: root
name: db

如果您真的想要,您可以使用和解析.ini文件,但与源代码中设置的数组相比,它可能非常慢,并且对我来说并没有那么大的意义。

请记住:您唯一可以信任的就是您的源代码,如果他们能得到它,那么无论如何您都完蛋了。

于 2013-02-26T12:28:54.480 回答