多数 PHP 程序同数据库交互。通常包含连接到数据库和使用帐户信息进行身份验证:
<?php
$host = 'example.org';
$username = 'myuser';
$password = 'mypass';
$db = mysql_connect($host, $username, $password);
?>
这个例子包含连接到数据库的全部信息,并保存为文件 db.inc。它在一个文件里保存了帐户信息,这看起来是非常剩心的。
问题出现在这个文件保存在在根文档(document root)下面的某个地方。这是非常普通的,因为这样使用 include
和 require 语句更加简单。但是这也将导致保露你的数据库帐户信息。
一定要记住,在根文档(document root)下的所有东西都有一个 URL 与之关联。例如,如果根文档(document root)在 /usr/local/apache/htdocs,当一个文件存储在 /usr/local/apache/htdocs/inc/db.inc 时,则可以通过 URL http://example.org/inc/db.inc访问到它。
可以断言多数 web 服务器将 .inc 文件当作普通文本对待,暴露账户信息的风险也是显然的。所有模块中的代码都会暴露是一个大问题,特别是账户信息尤其敏感。
当然,一个简单的解决方案是将所有模块放在根文档之外,这也是很好的方法。include
和 require 都可以访问文件系统路径,所以没有必要通过 URL 访问模块。这是不必要的风险。
如果你无法选择模块保存的位置,也就是说必须在根文档之下,可以在 httpd.conf 中添加如下内容(假设是 Apache):
<Files ~ "\.inc$">
Order allow,deny
Deny from all
</Files>
让 PHP 引擎处理模块并不是一个好办法。不论是将扩展名修改为 .php 还是使用 AddType 让 .inc 被认为是 PHP 文件。执行内容之外的代码是非常危险的,因为不是预期的行为可能造成未知的后果。然而,如果你的模块仅仅包含变量赋值(如示例中那样),这个风险会小一些。
保护数据库账户信息最好的方式在 David Sklar 和 Adam Trachtenberg 编写的《PHP Cookbook(O'Reilly)》中有所描述。创建一个文件 /path/to/secret-stuff,只有 root 可以读取(不是 nobody):
SetEnv DB_USER "myuser"
SetEnv DB_PASS "mypass"
用下面的方式在 httpd.conf 中包含这个文件:
Include "/path/to/secret-stuff"
现在可以在代码中使用 $_SERVER['DB_USER'] 和
$_SERVER['DB_PASS']。不光不需要将用户名和密码写入任何脚本,而且 web 服务器无法读取 secret-stuff 文件,这样其他用户不能通过编写脚本来读取账户信息(不论什么语言)。需要注意不要让如 phpinfo() 或者 print_r($_SERVER) 暴露这些变量信息。