在很长一段时间内,PHP作为服务器端脚本语言的最大卖点之一就是会为从表单提交的值自动建立一个全局变量。在PHP 4.1中,PHP的制作者们推荐了一个访问提交数据的替代手段。在PHP 4.2中,他们取消了那种老的做法!正如我将在这篇文章中解释的那样,作出这样的变化的目的是出于安全性的考虑。我们将研究PHP在处理表单提交及其它数据时的新的做法,并说明为什么这样做会提高代码的安全性。
这里有什么错误?
看看下面的这段PHP脚本,它用来在输入的用户名及口令正确时授权访问一个Web页面:
// 检查用户名及口令
if ($username == 'kevin' and $password == 'secret')
$authorized = true;
?>
Please enter your username and password:
PHP 4.2作了什么改变?
在PHP 4.2中,新安装的PHP中的register_globals选项默认为关闭,因此EGPCS值(EGPCS是Environment、Get、Post、Cookies、Server的缩写 -- 这是PHP中外部变量来源的全部范围)不会被作为全局变量来创建。当然,这个选项还可以通过手工来开启,但是PHP的开发者推荐你将其关闭。要贯彻他们的意图,你需要使用其它的方法来获取这些值。
从PHP 4.1开始,EGPCS值就可以从一组指定的数组中获得:
$_ENV -- 包含系统环境变量
$_GET -- 包含查询字符串中的变量,以及提交方法为GET的表单中的变量
$_POST -- 包含提交方式为POST的表单中的变量
$_COOKIE -- 包含所有cookie变量
$_SERVER -- 包含服务器变量,例如HTTP_USER_AGENT
$_REQUEST -- 包含$_GET、$_POST和$_COOKIE的全部内容
$_SESSION -- 包含所有已注册的session变量
在PHP 4.1之前,当开发者关闭register_globals选项(这也被考虑为提高PHP性能的一种方法)后,必须使用诸如$HTTP_GET_VARS这样的令人讨厌的名字来获取这些变量。这些新的变量名不仅仅短,而且它们还有其他优点。
首先,让我们在PHP 4.2中(也就是说关闭register_globals 选项)重写上面提到的代码:
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];
// 检查用户名和口令
if ($username == 'kevin' and $password == 'secret')
$authorized = true;
?>
Please enter your username and password:
但是这是不是意味着更多的输入?
是的,在象上面这样的简单程序中,使用PHP 4.2常常会增加输入量。但是,还是看看光明的一面吧 -- 你的程序终究是更安全了!
不过认真的说,PHP的设计者并没有完全忽视你的痛苦。在这些新数组中有一个特殊的其它所PHP变量都不具备的特征,它们是完全的全局变量。这对你有什么帮助呢?让我们先对我们的示例进行一下扩充。
为了使得站点中的多个页面可以使用用户名/口令论证,我们将我们用户认证程序写到一个include文件(protectme.php)中:
function authorize_user($authuser, $authpass)
{
$username = $_POST['username'];
$password = $_POST['password'];
// 检查用户名和口令
if ($username != $authuser or $password != $authpass):
?>
Please enter your username and password:
这对session有什么影响?
特別な $_SESSION 配列の導入は、実際にセッション コードを簡素化するのに役立ちます。セッション変数をグローバル変数として宣言し、どの変数が登録されているかを追跡する代わりに、$_SESSION['varname'] からすべてのセッション変数を簡単に参照できるようになりました。
次に、ユーザー認証の別の例を見てみましょう。今回は、セッションを使用して、サイトに滞在し続けるユーザーが認証されたことを示します。まず、PHP 4.0 バージョン (register_globals がオンになっている) を見てみましょう:
session_start();
if ($username == 'kevin' and $password == ' Secret')
{
$authorized = true;
session_register('authorized');
}
?>
最初のプログラムと同様に、このプログラムにもセキュリティ上の脆弱性があり、URL の末尾に ?authorized=1 を追加すると、セキュリティ対策を回避して直接アクセスできます。ページのコンテンツ。開発者は $authorized をセッション変数として扱い、同じ変数がユーザー入力を通じて簡単に設定できることを無視できます。
特別な配列 (PHP 4.1) を追加し、 register_globals (PHP 4.2) をオフにすると、プログラムは次のようになります:
session_start();
if ($username) == 'kevin' と $password == 'secret')
$_SESSION['authorized'] = true;
?>
もっと簡単ですか?通常の変数をセッション変数として登録する必要はなくなり、セッション変数を直接 ($_SESSION 配列内で) 設定し、同じ方法で使用するだけで済みます。プログラムが短くなり、どの変数がセッション変数であるかについて混乱が少なくなります。
概要
この記事では、PHP スクリプト言語の変更の根本的な理由について説明しました。 PHP 4.1 では、外部データにアクセスするために特別なデータ セットが追加されました。これらの配列は任意のスコープで呼び出すことができるため、外部データへのアクセスがより便利になります。 PHP 4.2 では、経験の浅い開発者が安全でない PHP コードを作成することを避けるために、これらの配列の使用を奨励するために、 register_globals はデフォルトでオフになっています。