第 3 章 数据库和 SQL

目录

暴露数据库信息
SQL 注入

暴露数据库信息

多数 PHP 程序同数据库交互。通常包含连接到数据库和使用帐户信息进行身份验证:

        <?php

        $host = 'example.org';
        $username = 'myuser';
        $password = 'mypass';

        $db = mysql_connect($host, $username, $password);

        ?>
    

这个例子包含连接到数据库的全部信息,并保存为文件 db.inc。它在一个文件里保存了帐户信息,这看起来是非常剩心的。

问题出现在这个文件保存在在根文档(document root)下面的某个地方。这是非常普通的,因为这样使用 includerequire 语句更加简单。但是这也将导致保露你的数据库帐户信息。

一定要记住,在根文档(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 文件当作普通文本对待,暴露账户信息的风险也是显然的。所有模块中的代码都会暴露是一个大问题,特别是账户信息尤其敏感。

当然,一个简单的解决方案是将所有模块放在根文档之外,这也是很好的方法。includerequire 都可以访问文件系统路径,所以没有必要通过 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) 暴露这些变量信息。