5、文件上傳 這樣的上傳代碼存在讀取任意文件和執行命令的重大問題。 下面的請求可以把/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變量的值,上傳覆蓋任意有寫權限的文件。 攻擊者還可以上傳PHP腳本執行主機的命令。 解決方法: PHP-4.0.3以后提供了is_uploaded_file和move_uploaded_file函數,可以檢查操作的文件是否是用戶上傳的文件,從而避免把系統文件拷貝到web目錄。 使用$HTTP_POST_FILES數組來讀取用戶上傳的文件變量。 嚴格檢查上傳變量。比如不允許是php腳本文件。 把PHP腳本操作限制在web目錄可以避免程序員使用copy函數把系統文件拷貝到web目錄。move_uploaded_file不受open_basedir的限制,所以不必修改php.ini里upload_tmp_dir的值。 把PHP腳本用phpencode進行加密,避免由于copy操作泄漏源碼。 嚴格配置文件和目錄的權限,只允許上傳的目錄能夠讓nobody用戶可寫。 對于上傳目錄去掉PHP解釋功能,可以通過修改httpd.conf實現: php_flag engine off #如果是php3換成php3_engine off 重啟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路徑自動被繼承。 |
溫馨提示:喜歡本站的話,請收藏一下本站!