浅析php中open_basedir存在安全隐患
先看一段我们不考虑open_basedir安全问题代码
在php写了句require_once ‘../Zend/Loader.php’; 报错:
Warning: require_once() [function.require-once]: open_basedir restriction in effect. File(../Zend/Loader.php) is not within the allowed path(s): (D:/phpnow/vhosts/zf.com;C:/Windows/Temp;) in D:/phpnow/vhosts/zf.com/index.php on line 6
Warning: require_once(../Zend/Loader.php) [function.require-once]: failed to open stream: Operation not permitted in D:/phpnow/vhosts/zf.com/index.php on line 6
Fatal error: require_once() [function.require]: Failed opening required '../Zend/Loader.php' (include_path='D:/phpnow/vhosts/zf.comZend;.;C:/php5/pear') in D:/phpnow/vhosts/zf.com/index.php on line 6字面分析是受到了open_basedir的限制,造成Operation not permitted(操作不被允许)。
打开php.ini跳转到open_basedir相关设置段落:
; open_basedir, if set, limits all file operations to the defined directory
; and below. This directive makes most sense if used in a per-directory
; or per-virtualhost web server configuration file. This directive is
; *NOT* affected by whether Safe Mode is turned On or Off.
;open_basedir =如果设置了open_basedir,那么所有能被操作的文件就只能限制在open_basedir指定的目录里面。 这个在虚拟主机里面这个指令相当有用。不管安全模式是否打开,这个指令都不受影响。 看来php.ini没有设置open_basedir。 打开apache虚拟主机配置文件:
代码如下 | 复制代码 |
<virtualhost *> |
里面的php_admin_value open_basedir就限定了操作目录。我这里是本地测试,安全因素不考虑,直接将 php_admin_value open_basedir “D:/phpnow/vhosts/zf.com;C:/Windows/Temp;” 删除掉,重新启动apache,
上面如果给利用完可以可随意删除服务器文件了,但是比较幸运的是目前php站点的安全配置基本是open_basedir+safemode,确实很无敌、很安全,即使在权限没有很好设置的环境中,这样配置都是相当安全的,当然了,不考虑某些可以绕过的情况。本文讨论两点开启open_basedir后可能导致的安全隐患(现实遇到的),一个也许属于php的一个小bug,另外一个可能是由于配置不当产生的。
一、open_basedir中处理文件路径时没有严格考虑目录的存在,这将导致本地包含或者本地文件读取的绕过。
看一个本地文件任意读取的例子:
代码如下 | 复制代码 |
<?php $file = $_GET['file']; preg_match("/^img/", $file) or die('error_file'); $file='/home/www/upload/'.$file; file_exists($file) or die('no_such_file'); $f = fopen("$file", 'r'); $jpeg = fread($f, filesize("$file")); fclose($f); Header("Content-type: image/jpeg"); Header("Content-disposition: inline; filename=test.jpg"); echo $jpeg; ?> |
虽然file是任意提交的,但是限制了前缀必须为img,我们如果想跳出目录读文件,比如,读取网站根目录下的config.php,我们得提交?file=img/../../config.php,但是此处有个限制条件,就是upload目录下不存在img文件夹,在windows文件系统里,系统不会去考虑目录存在不存在,会直接跳转目录从而导致漏洞;但linux文件系统非常严谨,它会仔细判断每一层目录是否存在,比如这里由于不存在img,则跳出去读取文件的时候直接报错。看如下一个示意图:
再看一个类似的本地包含的例子:
代码如下 | 复制代码 |
<?php include "aaa".$_GET['lang'].".php"; ?> |
由于linux文件系统的限制,我们无法利用旁注去包含tmp下的文件。
linux严谨的考虑在php那里显然没有得到深刻的体会。在开启了open_basedir的时候,php对传入的文件路径进行了取真实路径的处理,然后跟open_basedir中设置的路径进行比较:
代码如下 | 复制代码 |
…… path_len = strlen(resolved_name); |
但php在处理的时候忽略了检查路径是否存在,于是在开启了open_basedir时,上面那个文件读取的例子,我们可以使用?file=img/../../config.php来直接读取了,此时提交的路径已经被处理成/home/www/config.php了,所以不存在任何读取问题了。
问题由渗透测试的时候遇到绕过的情况从而导致疑问,经分析环境差异,然后xi4oyu牛指点有可能是open_basedir的问题后测试总结出这是php的一个小的bug,但是很有可能导致安全隐患。
二、open_basedir的值配置不当,有可能导致目录跨越。
很多管理员都知道设置open_basedir,但在配置不当的时候可能发生目录跨越的问题。
错误的配置:/tmp:/home/www,正确的配置:/tmp/:/home/www/
代码如下 | 复制代码 |
…… |
php考虑了以/结束的路径,但是如果没有/,就直接带入下文比较了。
于是,当新建一个网站为 /home/wwwoldjun/(均已经分别设置open_basedir),如果配置错误,则可以从/home/www/目录跳转到/home/wwwoldjun/目录。
举个渗透实例,某idc商在租用虚拟主机的时候如此分配空间/home/wwwroot/userxxx/、/home/wwwroot/useryyy/...,而open_basedir是这样错误配置的:/tmp:/home/wwwroot/userxxx、/tmp:/home/wwwroot/useryyy。如果我们想通过配置的错误轻易渗透下userxxx站点,我们该怎么做?
特殊值 . 指明脚本的工作目录将被作为基准目录。但这有些危险,因为脚本的工作目录可以轻易被 chdir() 而改变。
在 httpd.conf 文件中中,open_basedir 可以像其它任何配置选项一样用“php_admin_value open_basedir none”的方法关闭(例如某些虚拟主机中)。
在 Windows 中,用分号分隔目录。在任何其它系统中用冒号分隔目录。作为 Apache 模块时,父目录中的 open_basedir 路径自动被继承。
用 open_basedir 指定的限制实际上是前缀,不是目录名。也就是说“open_basedir = /dir/incl”也会允许访问“/dir/include”和“/dir/incls”,如果它们存在的话。如果要将访问限制在仅为指定的目录,用斜线结束路径名。例如:“open_basedir = /dir/incl/”。
利用php过滤恶意字符原理很简单我们只要定义好字符然后再利用foreach遍历恶意字符库,利用strpost检测用户提交的数据中有没有恶意字符库中字符即可实例了。例1,判断字符是否存在
代码如下 | 复制代码 |
function is_bad_chars($str){ |
根据上面实例我们可以做一个过滤关键字的实例
代码如下 | 复制代码 |
function outip($ip){//排除ip |
ip.txt文件中就是放一些你要过滤的词字了,这里面是每个字或词为一行
PHP验证码生这个功能常用于用用户注册登录或发布信息时一个安全验证的基本功能,下面小编来给大家介绍一些常用的PHP验证码生成代码与应用实例。例1,直接使用数组,此方法比较简单
代码如下 | 复制代码 |
<html> $arr=array(2,3,4,5,8,1,9,7,"a","b","c","d","e","f","中","国","南","北","大","小","多","少"); ?> <input type="submit" name="submit" value="do" /> echo “code:"; </body> <?php |
(以上语句另存为yz.php)
例2,也是用数组只不是数据多了一点
代码如下 | 复制代码 |
function UPCAbarcode($code) { UPCAbarcode('12345678901'); ?> |
例3,这个是一个比较完整的ajax刷新验证码实例
vcode.php
代码如下 | 复制代码 |
<?php $im = imagecreate(60,30);//定义图片宽度和高度 |
loginform.html
代码如下 | 复制代码 |
|
vcode.js
代码如下 | 复制代码 |
//该函数用来获取验证码 function getVCode() { //该函数用来验证验证码 |
mcrypt简单介绍
PHP程序员们在编写代码程序时,除了要保证代码的高性能之外,还有一点是非常重要的,那就是程序的安全性保障。PHP除了自带的几种加密函数外,还有功能更全面的PHP加密扩展库Mcrypt和Mhash。
其中,Mcrypt扩展库可以实现加密解密功能,就是既能将明文加密,也可以密文还原。
mcrypt 是 php 里面重要的加密支持扩展库,linux环境下:该库在默认情况下不开启。window环境下:PHP>=5.3,默认开启mcrypt扩展。
1、Mcrypt()库的安装
mcypt是一个功能十分强大的加密算法扩展库。在标准的PHP安装过程中并没有把Mcrypt安装上,但PHP的主目录下包含了libmcrypt.dll文件,所以我们只用将PHP配置文件中的这行:extension=php_mcrypt.dll前面的分号去掉,然后重启服务器就可以使用这个扩展库了。
支持的算法和加密模式
Mcrypt库支持20多种加密算法和8种加密模式,具体可以通过函数mcrypt_list_algorithms()和mcrypt_list_modes()来显示[1]加密算法
Mcrypt支持的算法有:
cast-128
gost
rijndael-128
twofish
arcfour
cast-256
loki97
rijndael-192
saferplus
wake
blowfish-compat
des
rijndael-256
serpent
xtea
blowfish
enigma
rc2
tripledes
加密模式
Mcrypt支持的加密模式有:
cbc
cfb
ctr
ecb
ncfb
nofb
ofb
stream
这些算法和模式在应用中要以常量来表示,写的时候加上前缀MCRYPT_和MCRYPT_来表示,如下面Mcrypt应用的
例子
DES算法表示为MCRYPT_DES;
ECB模式表示为MCRYPT_MODE_ECB;
代码如下 | 复制代码 |
<?php |
运行结果:
加密明文:我的名字是?一般人我不告诉他!
加密密文: 锍??]??q???L 笑 ??"? ?
还原:我的名字是?一般人我不告诉他!
<1>由例子中可看到,使用PHP加密扩展库Mcrypt对数据加密和解密之前,首先创建了一个初始化向量,简称为iv。由 $iv = mcrypt_create_iv(mcrypt_get_iv_size($cipher,$modes),MCRYPT_RAND);可见创建初始化向 量需要两个参数:size指定了iv的大小;source为iv的源,其中值MCRYPT_RAND为系统随机数。
<2>函数mcrypt_get_iv_size($cipher,$modes)返回初始化向量大小,参数cipher和mode分别指算法和加 密模式。
<3>加密函数$str_encrypt = mcrypt_encrypt($cipher,$key,$str,$modes,$iv); 该函数的5个参数分 别如下:cipher——加密算法、key——密钥、data(str)——需要加密的数据、mode——算法模式、 iv——初始化向量
<4>解密函数 mcrypt_decrypt($cipher,$key,$str_encrypt,$modes,$iv); 该函数和加密函数的参数几乎 一样,唯一不同的是data,也就是说data为需要解密的数据$str_encrypt,而不是原始数据$str。
注:加密和解密函数中的参数cipher、key和mode必须一一对应,否则数据不能被还原
总结
mcrypt库常量
Mcrypt库支持20多种加密算法和8种加密模式。可以通过函数mcrypt_list_algorithms()和mcrypt_list_modes()来查看。
一、在服务器端配置
安全,PHP代码编写是一方面,PHP的配置更是非常关键。
我们php手手工安装的,php的默认配置文件在 /usr/local/apache2/conf/php.ini,我们最主要就是要配置php.ini中的内容,让我们执行 php能够更安全。整个PHP中的安全设置主要是为了防止phpshell和SQL Injection的攻击,一下我们慢慢探讨。我们先使用任何编辑工具打开 /etc/local/apache2/conf/php.ini,如果你是采用其他方式安装,配置文件可能不在该目录。
(1) 打开php的安全模式
php的安全模式是个非常重要的内嵌的安全机制,能够控制一些php中的函数,比如system(),
同时把很多文件操作函数进行了权限控制,也不允许对某些关键文件的文件,比如/etc/passwd,
但是默认的php.ini是没有打开安全模式的,我们把它打开:
safe_mode = on
(2) 用户组安全
当safe_mode打开时,safe_mode_gid被关闭,那么php脚本能够对文件进行访问,而且相同
组的用户也能够对文件进行访问。
建议设置为:
safe_mode_gid = off
如果不进行设置,可能我们无法对我们服务器网站目录下的文件进行操作了,比如我们需要
对文件进行操作的时候。
(3) 安全模式下执行程序主目录
如果安全模式打开了,但是却是要执行某些程序的时候,可以指定要执行程序的主目录:
safe_mode_exec_dir = D:/usr/bin
一般情况下是不需要执行什么程序的,所以推荐不要执行系统程序目录,可以指向一个目录,
然后把需要执行的程序拷贝过去,比如:
safe_mode_exec_dir = D:/tmp/cmd
但是,我更推荐不要执行任何程序,那么就可以指向我们网页目录:
safe_mode_exec_dir = D:/usr/www
(4) 安全模式下包含文件
如果要在安全模式下包含某些公共文件,那么就修改一下选项:
safe_mode_include_dir = D:/usr/www/include/
其实一般php脚本中包含文件都是在程序自己已经写好了,这个可以根据具体需要设置。
(5) 控制php脚本能访问的目录
使用open_basedir选项能够控制PHP脚本只能访问指定的目录,这样能够避免PHP脚本访问
不应该访问的文件,一定程度上限制了phpshell的危害,我们一般可以设置为只能访问网站目录:
open_basedir = D:/usr/www
(6) 关闭危险函数
如果打开了安全模式,那么函数禁止是可以不需要的,但是我们为了安全还是考虑进去。比如,
我们觉得不希望执行包括system()等在那的能够执行命令的php函数,或者能够查看php信息的
phpinfo()等函数,那么我们就可以禁止它们:
disable_functions = system,passthru,exec,shell_exec,popen,phpinfo
如果你要禁止任何文件和目录的操作,那么可以关闭很多文件操作
disable_functions = chdir,chroot,dir,getcwd,opendir,readdir,scandir,fopen,unlink,delete,copy,mkdir, rmdir,rename,file,file_get_contents,fputs,fwrite,chgrp,chmod,chown
以上只是列了部分不叫常用的文件处理函数,你也可以把上面执行命令函数和这个函数结合,
就能够抵制大部分的phpshell了。
(7) 关闭PHP版本信息在http头中的泄漏
我们为了防止黑客获取服务器中php版本的信息,可以关闭该信息斜路在http头中:
expose_php = Off
比如黑客在 telnet www.12345.com 80 的时候,那么将无法看到PHP的信息。
(8) 关闭注册全局变量
在PHP中提交的变量,包括使用POST或者GET提交的变量,都将自动注册为全局变量,能够直接访问,
这是对服务器非常不安全的,所以我们不能让它注册为全局变量,就把注册全局变量选项关闭:
register_globals = Off
当然,如果这样设置了,那么获取对应变量的时候就要采用合理方式,比如获取GET提交的变量var,
那么就要用$_GET['var']来进行获取,这个php程序员要注意。
(9) 打开magic_quotes_gpc来防止SQL注入
SQL注入是非常危险的问题,小则网站后台被入侵,重则整个服务器沦陷,
所以一定要小心。php.ini中有一个设置:
magic_quotes_gpc = Off
这个默认是关闭的,如果它打开后将自动把用户提交对sql的查询进行转换,
比如把 ' 转为 '等,这对防止sql注射有重大作用。所以我们推荐设置为:
magic_quotes_gpc = On
(10) 错误信息控制
一般php在没有连接到数据库或者其他情况下会有提示错误,一般错误信息中会包含php脚本当
前的路径信息或者查询的SQL语句等信息,这类信息提供给黑客后,是不安全的,所以一般服务器建议禁止错误提示:
display_errors = Off
如果你却是是要显示错误信息,一定要设置显示错误的级别,比如只显示警告以上的信息:
error_reporting = E_WARNING & E_ERROR
当然,我还是建议关闭错误提示。
(11) 错误日志
建议在关闭display_errors后能够把错误信息记录下来,便于查找服务器运行的原因:
log_errors = On
同时也要设置错误日志存放的目录,建议根apache的日志存在一起:
error_log = D:/usr/local/apache2/logs/php_error.log
注意:给文件必须允许apache用户的和组具有写的权限。
相关文章
- 作为前端,一直以来都知道HTTP劫持与XSS跨站脚本、CSRF跨站请求伪造。防御这些劫持最好的方法是从后端入手,前端能做的太少。而且由于源码的暴露,攻击者很容易绕过防御手段。但这不代表我们去了解这块的相关知识是没意义的,本文的许多方法,用在其他方面也是大有作用。...2021-05-24
- 普通关闭 我的mysql是自己下载的tar包,自己设定安装目录来安装的。停止mysql服务,说来简单,但不知道的话,还真是挠头。在这和mysql入门的同学们共享:)正确方法是,进入mysql的bin目录下,然后执行./mysqladmin -uroot -p shut...2015-11-24
- 这篇文章主要介绍了C#实现线程安全的简易日志记录方法,比较实用的功能,需要的朋友可以参考下...2020-06-25
- 系统:centos 5.9 环境:apache 2.2.25 tomcat 7.0.42 jdk 1.7.0 1.安装apache 我这里是直接yum安装的,如果你们要编译安装也不是不行. 代码如下 ...2016-01-28
- 这篇文章主要介绍了php判断邮箱地址是否存在的方法,php判断邮箱地址是否存在的方法有两种,感兴趣的朋友可以参考一下...2016-02-18
- 当你第一次在机器上安装MySQL时,mysql数据库中的授权表是这样初始化的:你可以从本地主机(localhost)上以root连接而不指定口令。root用户拥有所有权限(包括管理权限) 并可做任何事情。...2013-09-19
- 这篇文章主要介绍了c# 判断指定文件是否存在的简单实现,需要的朋友可以参考下...2020-06-25
- open_basedir的作用就是指定目录位置了,意思是将PHP 所能打开的文件限制在指定的目录树,包括文件本身了,并且不受是不是安全模式的影响。 如下是php.ini中的原文...2016-11-25
- 偶这里是针对的WIN平台,现在的站长大部分都用WIN2003,相信没几个站长用低版本儿的操作系统的!...2016-01-27
- 本文章以自己的一些经验来告诉你黑客朋友们会怎么利用你数据库的sql漏洞来把你的数据库下载哦,有需要的同这参考一下本文章。 在数据库中建立一张表: 代码...2016-11-25
- 程序如下: $file_name = "info_check.exe"; $file_dir = "/public/www/download/"; if (!file_exists($file_dir . $file_name)) { //检查文件是否存在 ...2016-11-25
- 今天小编就为大家分享一篇python Popen 获取输出,等待运行完成示例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-05-06
- 收集和分发数据是网络管理的职责之一,而且必须确保这些数据的准确性和安全性。不管它们是什么操作系统,数据库服务器需要特殊的管理以保证操作上的安全性。 良好的安...2016-11-25
- 这篇文章主要介绍了Window.Open打开窗体和if嵌套代码的相关资料,需要的朋友可以参考下...2016-04-18
- VC判断进程是否存在?比如我想知道记事本是否运行,要用到哪些函数等实例,需要的朋友可以参考下...2020-04-25
- $_SERVER[’PHP_SELF’]在开发的时候常会用到,一般用来引用当前网页地址,并且它是系统自动生成的全局变量,也会有什么问题么?让我们先看看下面的代码吧: <form ac...2016-11-25
- 这篇文章主要介绍了C++检查某个文件或目录是否存在的函数,是Windows应用程序设计中非常常见的实用技巧,需要的朋友可以参考下...2020-04-25
- <?php /** * @name date safe class 0.1 * @author kevin xu * @copyright kenvin E-mail:gincn@cn.cashboxparty.com MSN:gincn@live.cn */ interface dateSa...2016-11-25
- 在编译器未优化的情况下顺序如下:1.new operator分配适当的内存;2.在分配的内存上构造Singleton对象;3.内存地址赋值给_instance...2020-04-25
Mongodb 崩溃报错 Too many open files的问题解析
这篇文章主要介绍了Mongodb 崩溃报错 Too many open files的问题,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2020-12-30