热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

用PHP4.2书写安全的脚本

用PHP4.2书写安全的脚本
原著:Kevin Yank 转自:www.linuxforum.net (恭喜再此开通)

在很长一段时间内,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:


" method="POST">

Username:

Password:






OK,我相信大约半数的读者会不屑的说“太愚蠢了-- 我不会犯这样的错误的!”但是我保证有很多的读者会想“嗨,没什么问题啊,我也会这么写的!”当然还会有少数人会对这个问题感到困惑(“什么是PHP?”)。PHP被设计为一个“好的而且容易的”脚本语言,初学者可以在很短的时间内学会使用它;它也应该能够避免初学者犯上面的错误。
再回到刚才的问题,上面的代码中存在的问题是你可以很容易地获得访问的权力,而不需要提供正确的用户名和口令。只在要你的浏览器的地址栏的最后添加?authorized=1。因为PHP会自动地为每一个提交的值创建一个变量 -- 不论是来自动一个提交的表单、URL查询字符串还是一个COOKIE -- 这会将$authorized设置为1,这样一个未授权的用户也可以突破安全限制。
那么,怎么简单地解决这个问题呢?只要在程序的开头将$authorized默认设置为false。这个问题就不存在了!$authorized是一个完全在程序代码中创建的变量;但是为什么开发者得为每一个恶意的用户提交的变量担心呢?

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:


" method="POST">

Username:

Password:






正如你看到的,我所需要做的只是在代码的开始增加下面两行:
$username = $_REQUEST['username'];
$password = $_REQUEST['password'];
因为我们希望用户名和密码是由用户提交的,所以我们从$_REQUEST数组中获取这些值。使用这个数组使得用户可以自由选择传递方式:通过URL查询字符串(例如允许用户创建书签时自动输入他们的证书)、通过一个提交的表单或者是通过一个COOKIE。如果你想要限制只能通过表单提交证书(更精确地说,是通过HTTP POST请求),你可以使用$_POST数组:
$username = $_POST['username'];
$password = $_POST['password'];
除了“引入”这两个变量以外,程序代码没有任何改变。简单地关闭register_globals选项促使开发者更进一步了解哪些数据是来自外部的(不可信任的)资源。
请注意这里还有一个小问题:PHP中默认的error_reporting设置仍然是E_ALL & ~E_NOTICE,因此如果“username”和“password”这两个值没有被提交,试图从$_REQUEST数组或$_POST数组中获得这两个值并不会招致任何错误信息。如晨不你的PHP程序需要严格的错误检查,你还需要增加一些代码以首先检查这些变量。

但是这是不是意味着更多的输入?

是的,在象上面这样的简单程序中,使用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:


" method="POST">

Username:

Password:



exit();
endif;
}
?>
现在,我们刚才的页面看上去将是这样的:
require('protectme.php');
authorize_user('kevin','secret');
?>

很简单,很清晰明了,对不对?现在是考验你的眼力和经验的时候了 -- 在authorize_user 函数中少了什么?
在函数中没有申明$_POST是一个全局变量!在php 4.0中,当register_globals开启时,你需要增加一行代码以在函数中获取$username和$password变量:
function authorize_user($authuser, $authpass)
{
global $username, $password;
...
在PHP中,和其它具有类似语法的语言不同,函数外的变量在函数中不能自动获得,你需要象上面所说明的那样增加一行以指定其来自global范围。
在PHP 4.0中,当关闭register_globals以提供安全性时,你可以使用$HTTP_POST_VARS数组以获得你的表单提交的值,但是你还是需要从全局范围导入这个数组:
function authorize_user($authuser, $authpass)
{
global $HTTP_POST_VARS;
$username = $HTTP_POST_VARS['username'];
$password = $HTTP_POST_VARS['password'];
但是在PHP 4.1及以后的版本中,特殊的$_POST变量(以及上面提到的其它变量)可以在所有范围内使用。这就是不需要在函数中申明$_POST变量是一个全局变量的原因:
function authorize_user($authuser, $authpass)
{
$username = $_POST['username'];
$password = $_POST['password'];

这对session有什么影响?

特殊的$_SESSION数组的引入实际上有助于简化session代码。你不需要将session变量申明为全局变量,然后再去留意哪些变量被注册了,你现在可以简单地从$_SESSION['varname']中引用你所有的session变量。
现在让我们来看看另一个用户认证的例子。这一次,我们使用sessions以标志一个在你的网站继续逗留的用户已经经过了用户认证。首先,我们来看看PHP 4.0版本(开启register_globals):
session_start();
if ($username == 'kevin' and $password == 'secret')
{
$authorized = true;
session_register('authorized');
}
?>





和刚开始的程序一样,这个程序也存在安全漏洞,在URL的最后加上?authorized=1可以绕过安全措施直接访问页面内容。开发者可以将$authorized视为一个session变量而忽视了可以很容易地通过用户输入设置同样的变量。
当我们增加了我们的特殊的数组(PHP 4.1)并关闭register_globals(PHP 4.2)后,我们的程序将是这样的:
session_start();
if ($username == 'kevin' and $password == 'secret')
$_SESSION['authorized'] = true;
?>





是不是更加简单了?你不再需要再将普通的变量注册为一个session变量,你只需要直接设置session变量(在$_SESSION数组中),然后用同样的方法使用它。程序变得更短了,而且对于什么变量是session变量也不会引起混乱!

总结

在这篇文章中,我解释了PHP脚本语言作出改变的深层原因。在PHP 4.1中,添加了一组特殊数据以访问外部数据。这些数组可以在任何范围内调用,这使得外部数据的访问更方便。在PHP 4.2中,register_globals被默认关闭以鼓励使用这些数组以避免无经验的开发者编写出不安全的PHP代码。
推荐阅读
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 禁止程序接收鼠标事件的工具_VNC Viewer for Mac(远程桌面工具)免费版
    VNCViewerforMac是一款运行在Mac平台上的远程桌面工具,vncviewermac版可以帮助您使用Mac的键盘和鼠标来控制远程计算机,操作简 ... [详细]
  • 本文介绍了使用PHP实现断点续传乱序合并文件的方法和源码。由于网络原因,文件需要分割成多个部分发送,因此无法按顺序接收。文章中提供了merge2.php的源码,通过使用shuffle函数打乱文件读取顺序,实现了乱序合并文件的功能。同时,还介绍了filesize、glob、unlink、fopen等相关函数的使用。阅读本文可以了解如何使用PHP实现断点续传乱序合并文件的具体步骤。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文介绍了使用CentOS7.0 U盘刻录工具进行安装的详细步骤,包括使用USBWriter工具刻录ISO文件到USB驱动器、格式化USB磁盘、设置启动顺序等。通过本文的指导,用户可以轻松地使用U盘安装CentOS7.0操作系统。 ... [详细]
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
author-avatar
大胡子姐姐爱油面巾塞肉
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有