网络安全

位置:IT落伍者 >> 网络安全 >> 浏览文章

理解PHP及其安全问题的入门知识


发布日期:2023年08月14日
 
理解PHP及其安全问题的入门知识

有时候您的业务可能涉及到 PHP 应用程序的安全性当您遇到审计任务时您知道如何执行查找吗?本系列将带您进入 PHP并帮您在一定程序上了解它让您在进行安全审计时知道查找什么 部分向您介绍 register_globals 设置

入门知识

我在此假定您对 PHP 的语法有一个大致的了解至少能够编写Hello World之类的程序如果您不具备基础知识则请首先学习 PHP 手册和某些基本的 PHP 教程(参阅 参考资料)很多出版商都有关于 PHP 的好书建议初学者一开始先看看入门书籍或食谱形式的书籍

在生产环境的准确副本上执行审计您不需要复制硬件但是需要确保软件版本尽量和实际的完全一样PHP 配置必须精确匹配这一点在 phpini 文件中htaccess 文件的 Apache 指令中或在  中已经指定您需要准备一个单独的环境因为您将显示和记录可能包含敏感的密码及其他信息的错误此外您将尝试中断站点的安全性这一点是您在活动应用程序中极力避免的

第一步是将 PHP 的 error_reporting 设置更改为 E_ALL设置更改后每当使用未初始化的变量进行错误的文件访问及发生其他(大多数)无害错误时PHP 都会报告一条警告消息但也存在这是一个潜在攻击矢量的可能性这些错误一般情况下只是表明编程草率所以如果这是您的代码您把它们清除掉即可

该设置如下所示

error_reporting = E_ALL

如果您不知道 phpini 文件在哪里则可以通过创建包含以下文本的 php 脚本来查找

<?php

phpinfo();

输出的上面部分有一行列出了 PHP 查找 phpini 的位置

PHP 查找 phpini 的位置

[[The No Picture]]

值可能会有些变化但 /usr/local/lib/phpini 是大多数 UNIX? 系统上的公共位置C:\php\phpini 或 C:\WINDOWS\phpini 是大多数 Microsoft? Windows? 系统上的公共位置如果该文件不存在则创建一个并在文件中键入上面的 error_reporting 行即可修改 phpini 文件后需要重启 Web 服务器PHP 才能启用新设置

如果您以前没有创建 phpinfo() 页面则可以现在创建第二个主要部分的标签是配置它包含许多关于如何设置 PHP 的有用信息该部分包括三列设置名称本地值 和 xmaster 值主值是通过 phpini 指令为您机器上的所有 PHP 脚本全局设置的值本地值是对当前脚本生效的值对它有影响的有htaccess 设置 的 <Location> 或 <Directory> 部分中的设置和 PHP 脚本中的 ini_set 调用在运行时只有某些设置是可更改的请参阅 参考资料中的 PHP 手册以获取详细信息

还需要自定义的另外两种设置是 display_errors 和 log_errors您至少需要启用这两种设置中的一种或者两种都启用log_errors 通知 PHP 将注意警告或错误记录在文件中display_errors 将这些被记录下来的注意警告和错误显示在屏幕上它们不互相排斥至少启用它们中的一个可以有效地发现可能导致安全漏洞的编程错误

应该查找哪些种类的安全问题?

值得庆幸的是导致安全漏洞的很多编程错误在 PHP 中不可能存在堆栈和缓沖溢出是 C 和 C++ 环境中两个常见的问题因为 PHP 可以为您管理记忆所以 PHP 代码不会导致堆栈和缓沖溢出

然而PHP 本身也是使用 C 语言编写的有时记忆问题深至 PHP 的核面因此您需要时时关注安全公报和更新PHP 在其 Web 站点(参见 参考资料)公布新 PHP 版本并说明是否包含安全修补程序

PHP 应用程序中的大多数问题与使用用户提供的数据有关在使用它和对它执行操作前未曾预先验证和消毒您可能听说过称为 crosssite scripting (XSS) 的漏洞XSS 通过提供程序不期望的输入然后利用程序对无赖输入的处理方式发动进攻编写良好的程序可以避免这些假定在机场安全方面PHP 程序用于检查旅客的行李

其他问题是一些细微的逻辑错误例如检查一系列参数看看是否批准某个用户访问某种资源是否把括弧放错位置以至于某些用户进入了他们原本不该到的地方我们希望您的应用程序组织良好并具有这种集中式逻辑

识别用户输入

最棘手的一件事情是如何从外部源(如某个用户别的 Web 站点或某些其他资源)和已经验证的数据中区分出不受信任的输入有人提出了不相信一切的观点即不管来自何处对于所有函数都要验证其数据这一做法会牵涉到以下几件事情第一验证在不同的上下文中意味着不同的事情第二在应用程序的所有级别上快速执行验证是一件枯燥乏味和易于出错的事情第三您是在审计应用程序而不是在从头重新编写它您需要通过现有代码来跟蹤用户输入而不能用验证函数包装您看到的每个变量

不期望的用户输入

用户输入从何而来?第一个源是 GETPOST 和 COOKIE 数据一般称为 GPC 数据此数据的可识别程序依赖于一个有争议的 phpini 设置register_globals在 PHP V 以后register_globals 默认情况下被设置为 Off但是几年前在 PHP 中register_globals 的默认值是打开的所以存在很多需要它的代码

register_globals 本身并非安全风险但是它为跟蹤用户输入和确保应用程序安全增加了难度为什么会这样?因为如果打开 register_globals在全局名称空间和 $_GET$_POST 或 $_COOKIE 数组中将创建 GETPOST 和 COOKIE 传递到 PHP 脚本的所有变量

下面是工作方式及其重要性的示例

清单 COOKIE 的安全性

<?php

// See if the user has the secret cookie

if (!empty($_COOKIE[secret])) {

$authorized = true;

}

// Now lets go through a list of press releases and show them

$releases = get_press_releases();

foreach ($releases as $release) {

// Some releases are restricted Only show them to people who can

// see secrets

if ($release[secret]) {

if (!$authorized) {

continue;

}

}

// We must be allowed to see it

showRelease($release);

}

您应该注意几件事第一依靠 cookie 来判断用户是否已通过身份验证不是个好主意 —— 因为人们可以很容易地设置自己的 cookie 值我们将在另外一篇文章中叙述这一点无论如何此脚本的缺点在于如果打开 register_globals它就不具备安全性了

下面介绍名为 pressphp 的脚本一般来说当用户访问 press 发行版的脚本时其浏览器将显示

现在注意当用户擅自将其更改为 ?authorized= 时将发生什么事?

看看前面的代码仅当用户使用 cookie 时才设置 $authorized它永远不会被设置为假后来引入了 register_globals —— 它取代了刚才使用的 $_GET[authorized]同时在全局范围内还存在一个值为 的变量 $authorized因此即使用户没有通过 cookie 检查$authorized 后来在 foreach 循环中引用时仍然会被验证为真

修复此缺陷可以使用两种方式其一当然是关闭 register_globals如果关闭它对您的生产站点没有影响则这是个好主意您需要测试一下应用程序确保它没有因此中断运行

另一种方式有点像防御性编程我们只需要将 cookie 检查更改为以下形式即可

清单 使用 COOKIE 提高安全性

<?php

// See if the user has the secret cookie

$authorized = false;

if (!empty($_COOKIE[secret])) {

$authorized = true;

}

这时当用户将 ?authorized= 添加到脚本 URL 时$authorized 变量仍然被设置为 —— 但是它随即会被 $authorized = false 覆盖只有那些实际具有秘密 cookie 的用户才能看到受限的 press 发行版他们仍然可以设计自己的 cookie

审计代码的教训设法关闭 register_globals如果不打开 register_globals 应用程序就不能运行并且您无法修改它或者在应用程序必须运行的地方您无法控制 PHP 配置则需要在条件块中查找所有全局变量设置或者通过某些函数调用进入全局范围如果 register_globals 为打开状态则这两种情形都是由用户将变量设置为任意值引起的

找到这些变量的好办法是将 phpini 设置 error_reporting 设置为 E_ALL同时使用 log_errors 或 display_errors这样所有 PHP 警告和错误都会被分别记录在文件中或显示在屏幕上每当使用未初始化的变量(假定具有值)时您将得到一条 E_NOTICE这像 C 和 Java? 语言中那样仍然与让 PHP 要求声明 变量有所不同结果当我们的第一个版本的脚本运行时出现的错误消息是

Notice: Undefined variable: authorized in C:\var\www\articles\pressphp

on line                

上一篇:防止重复在线,统计在线人数的办法

下一篇:用Suhosin加强PHP脚本语言安全性