明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

PHP安全設置(3)

[摘要]5、文件上傳 php的文件上傳機制是把用戶上傳的文件保存在php.ini的upload_tmp_dir定義的臨時目錄(默認是系統(tǒng)的臨時目錄,如:/tmp)里的一個類似phpxXuoXG的隨機臨時文件,程序執(zhí)行結(jié)束,該臨時文件也被刪除。PHP給上傳的文件定義了四個變量:(如form變量名是file,...
5、文件上傳

php的文件上傳機制是把用戶上傳的文件保存在php.ini的upload_tmp_dir定義的臨時目錄(默認是系統(tǒng)的臨時目錄,如:/tmp)里的一個類似phpxXuoXG的隨機臨時文件,程序執(zhí)行結(jié)束,該臨時文件也被刪除。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") {
copy($file, "/usr/local/apache/htdocshttp://img6-2.22122511.com/upload/technique_8/".$file_name);
echo "文件".$file_name."上傳成功!點擊繼續(xù)上傳";
exit;
}
?>




content="text/html; charset=gb2312">



上傳文件:








這樣的上傳代碼存在讀取任意文件和執(zhí)行命令的重大問題。

下面的請求可以把/etc/passwd文檔拷貝到web目錄/usr/local/apache/htdocs/test(注意:這個目錄必須nobody可寫)下的attack.txt文件里:

http://victim/test_5.php?upload=1&file=/etc/passwd&file_name=attack.txt

然后可以用如下請求讀取口令文件:

http://victim/test/attack.txt

攻擊者可以把php文件拷貝成其它擴展名,泄漏腳本源代碼。

攻擊者可以自定義form里file_name變量的值,上傳覆蓋任意有寫權(quán)限的文件。

攻擊者還可以上傳PHP腳本執(zhí)行主機的命令。

解決方法:

PHP-4.0.3以后提供了is_uploaded_file和move_uploaded_file函數(shù),可以檢查操作的文件是否是用戶上傳的文件,從而避免把系統(tǒng)文件拷貝到web目錄。

使用$HTTP_POST_FILES數(shù)組來讀取用戶上傳的文件變量。

嚴格檢查上傳變量。比如不允許是php腳本文件。

把PHP腳本操作限制在web目錄可以避免程序員使用copy函數(shù)把系統(tǒng)文件拷貝到web目錄。move_uploaded_file不受open_basedir的限制,所以不必修改php.ini里upload_tmp_dir的值。

把PHP腳本用phpencode進行加密,避免由于copy操作泄漏源碼。

嚴格配置文件和目錄的權(quán)限,只允許上傳的目錄能夠讓nobody用戶可寫。

對于上傳目錄去掉PHP解釋功能,可以通過修改httpd.conf實現(xiàn):


php_flag engine off
#如果是php3換成php3_engine off




重啟apache,upload目錄的php文件就不能被apache解釋了,即使上傳了php文件也沒有問題,只能直接顯示源碼。

6、命令執(zhí)行

下面的代碼片斷是從PHPNetToolpack摘出,詳細的描述見:

http://www.securityfocus.com/bid/4303

<>
//test_6.php
system("traceroute $a_query",$ret_strs);
?>



由于程序沒有過濾$a_query變量,所以攻擊者可以用分號來追加執(zhí)行命令。

攻擊者輸入如下請求可以執(zhí)行cat /etc/passwd命令:

http://victim/test_6.php?a_query=www.example.com;cat /etc/passwd

PHP的命令執(zhí)行函數(shù)還有system(), passthru(), popen()和``等。命令執(zhí)行函數(shù)非常危險,慎用。如果要使用一定要嚴格檢查用戶輸入。

解決方法:

要求程序員使用escapeshellcmd()函數(shù)過濾用戶輸入的shell命令。

啟用safe_mode可以杜絕很多執(zhí)行命令的問題,不過要注意PHP的版本一定要是最新的,小于PHP-4.2.2的都可能繞過safe_mode的限制去執(zhí)行命令。

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攻擊。

對于數(shù)字類型的字段,很多程序員會這樣寫:

select * from test where id=$id



由于變量沒有用單引號擴起來,就會造成sql_inject攻擊。幸虧MySQL功能簡單,沒有sqlserver等數(shù)據(jù)庫有執(zhí)行命令的SQL語句,而且PHP的mysql_query()函數(shù)也只允許執(zhí)行一條SQL語句,所以用分號隔開多條SQL語句的攻擊也不能奏效。但是攻擊者起碼還可以讓查詢語句出錯,泄漏系統(tǒng)的一些信息,或者一些意想不到的情況。

解決方法:

要求程序員對所有用戶提交的要放到SQL語句的變量進行過濾。

即使是數(shù)字類型的字段,變量也要用單引號擴起來,MySQL自己會把字串處理成數(shù)字。

在MySQL里不要給PHP程序高級別權(quán)限的用戶,只允許對自己的庫進行操作,這也避免了程序出現(xiàn)問題被 SELECT INTO OUTFILE ... 這種攻擊。

8、警告及錯誤信息

PHP默認顯示所有的警告及錯誤信息:

error_reporting = E_ALL & ~E_NOTICE
display_errors = On



在平時開發(fā)調(diào)試時這非常有用,可以根據(jù)警告信息馬上找到程序錯誤所在。

正式應用時,警告及錯誤信息讓用戶不知所措,而且給攻擊者泄漏了腳本所在的物理路徑,為攻擊者的進一步攻擊提供了有利的信息。而且由于自己沒有訪問到錯誤的地方,反而不能及時修改程序的錯誤。所以把PHP的所有警告及錯誤信息記錄到一個日志文件是非常明智的,即不給攻擊者泄漏物理路徑,又能讓自己知道程序錯誤所在。

修改php.ini中關(guān)于Error handling and logging部分內(nèi)容:

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

如果覺得有些函數(shù)還有威脅,可以設置php.ini里的disable_functions(這個選項不能在httpd.conf里設置),比如:

disable_functions = phpinfo, get_cfg_var



可以指定多個函數(shù),用逗號分開。重啟apache后,phpinfo, get_cfg_var函數(shù)都被禁止了。建議關(guān)閉函數(shù)phpinfo, get_cfg_var,這兩個函數(shù)容易泄漏服務器信息,而且沒有實際用處。

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",如果它們存在的話。如果要將訪問限制在僅為指定的目錄,用斜線結(jié)束路徑名。例如:"open_basedir = /dir/incl/"。

可以設置多個目錄,在Windows中,用分號分隔目錄。在任何其它系統(tǒng)中用冒號分隔目錄。作為Apache模塊時,父目錄中的open_basedir路徑自動被繼承。




相關(guān)文章