什麼是PHP安全模式:safe_mode 簡單說,PHP安全模式就是以安全模式運行php。 php的安全模式提供一個基本安全的共享環境,在一個有多個用戶賬戶存在的php開放的web服務器上。當一個web服務器上運行的php打開了安全模式,那麼一些函數將被徹底的禁止,而且會限制一些可用的功能。 在安全模式下,一些嘗試訪問文件系統的函數功能將被限制。運行web服務器用戶id,若是想要操做某個文件,則必須擁有該文件讀取或者寫入的訪問權限,實現這個限制功能對於php來講是沒有問題的。在安全模式開啓的時候,嘗試讀取或者寫入一個本地文件的時候,php將檢查當前訪問用戶是不是該目標文件的全部者。若是不是全部者,則該操做會被禁止。(寫入權限:在較低級別的文件訪問權限下,可能會容許讀取或者寫入系統操做系統的文件,經過php的安全模式實現了防止你操做另一個用戶文件的操做。固然,一個web服務器可能可以訪問一個具備全局寫入權限的任意文件。) 當安全模式打開的時候,如下函數列表的功能將會受到限制: chdir, move_uploaded_file, chgrp, parse_ini_file, chown, rmdir, copy, rename, fopen, require, highlight_file, show_source, include, symlink, link, touch, mkdir, unlink 一樣的,一些php擴展中的函數也將會受到影響。(加載模塊:在安全模式下dl函數將被禁止,若是要加載擴展的話,只能修改php.ini中的擴展選項,在php啓動的時候加載) 在php安全模式打開的時候,須要執行系統程序的時候,必須是在safe_mode_exec_dir選項指定目錄的程序,不然執行將失敗。即便容許執行,那麼也會自動的傳遞給escapeshellcmd函數進行過濾。 如下執行命令的函數列表將會受到影響: exec,shell_exec,passthru,system,popen 另外,背部標記操做符(`)也將被關閉。 當運行在安全模式下,雖然不會引發錯誤,可是putenv函數將無效。一樣的,其餘一些嘗試改變php環境變量的函數set_time_limit, set_include_path也將被忽略。 如何開啓PHP安全模式(請注意,PHP5.3將再也不有安全模式) 打開或者關閉php的安全模式是利用php.ini中的safe_mode選項: safe_mode=On(使用安全模式) safe_mode=Off(關閉安全模式) 在apache的httpd.conf中VirtualHost的相應設置方法 php_admin_flag safe_mode On(使用安全模式) php_admin_flag safe_mode Off(關閉安全模式) 或者: php_admin_value safe_mode1(使用安全模式) php_admin_value safe_mode0(關閉安全模式) 啓用安全模式後的影響: 當函數在訪問文件系統的時候將進行文件全部者的檢查。缺省狀況下,會檢查該文件全部者的用戶id,當你可以修改文件全部者的組id(gid)爲safe_mode_gid選項所指定的。 若是你有一個共享庫文件在你的系統上,當你碰到須要include或require的時候,那麼你可使用safe_mode_include_dir選項來設置你的路徑,保證你的代碼正常工做。(包含路徑:若是你想要使用safe_mode_include_dir選項包含更多的包含路徑,那麼你能夠象include_path選項同樣,在unix/linux系統下使用冒號進行分割,在windows下使用分號進行分割) 好比你想要在安全模式下包含/usr/local/include/php下的文件,那麼你能夠設置選項爲: safe_mode_include_dir=/usr/local/include/php 若是你的包含的文件是須要執行的,那麼你能夠設置safe_mode_exec_dir選項。 好比你須要/usr/local/php-bin路徑下的文件是能夠執行的,那麼能夠設置選項爲: safe_mode_exec_dir=/usr/local/php-bin (可執行:若是你執行的程序在/usr/bin目錄下,那麼你能夠把這些的二進制文件,鏈接到你指定選項下可以執行的路徑) 若是你想設置某些環境變量,那麼可使用safe_mode_allowed_env_vars選項。這個選項的值是一個環境變量的前綴,缺省是容許php_開頭的環境變量,若是你想要改變,能夠設置該選項的值,多個環境變量前綴之間使用逗號進行分割。 好比下面容許時區的環境變量tz,那麼修改該選項的值爲: safe_mode_allowed_env_vars=php_,tz 除了安全模式之外,php還提供了許多其餘許多特徵來保證php的安全。 一、[隱藏php的版本號] 你可以在php.ini裏使用expose_php選項來防止web服務器泄露php的報告信息。以下: expose_php=on 利用整個設置,你可以阻礙一些來自自動腳本針對web服務器的攻擊。一般狀況下,http的頭信息裏面包含了以下信息: server:apache/1.3.33(unix)php/5.2.4mod_ssl/2.8.16openssl/0.9.7c 在expose_php選項打開之後,php的版本信息將不包含在上面的頭信息裏。 固然,用戶訪問網站的時候一樣可以看到.php的文件擴展名。若是你想整個的使用不一樣的文件擴展名,你須要在httpd.conf中找到以下這行: addtype application/x-httpd.php 你就能夠修改.php爲任何你喜歡的文件擴展名。你可以指定任意多個的文件擴展名,中間使用空格進行分割。若是你想在服務器端使用php來解析.html和.htm文件的時候,那麼你設置選項以下: addtype application/x-httpd.html.htm (解析html:配置你的web服務器使用php去解析全部的html文件,可是若是非服務器端代碼也須要php去解析,會影響服務器的性能。靜態頁面你可使用不一樣的擴展名,這樣可以消除對php腳本引擎的依賴,加強性能。) 二、[文件系統安全] 安全模式限制了腳本全部者只能訪問屬於本身的文件,可是你可使用open_basedir選現來指定一個你必須訪問的目錄。若是你指定了一個目錄,php將拒絕訪問除了該目錄和該目錄子目錄的其餘目錄。open_basedir選項可以工做在安全模式以外。 限制文件系統只能訪問/tmp目錄,那麼設置選項爲: open_basedir=/tmp 三、[函數訪問控制] 你可以在disable_functions選項中使用逗號分割來設定函數名,那麼這些函數將在php腳本中被關閉。這個設置可以工做在安全模式以外。 disable_functions=dl 固然,一樣的你可以使用disable_classes選項來關閉對一些類的訪問。 四、[數據庫安全] 假設你的php腳本中包含一個基於表單值來執行的mysql查詢: $sql=」update mytable set col1=」.$_post["value"].」where col2=’somevalue’」; $res=mysql_query($sql,$db); 你但願$_post["value"]包含一個整數值來更新你的列col1。但是,一個惡意用戶可以輸入一個分號在表單字段裏,接着,是一段他/她想被任意執行的sql語句。 舉例,假設下面是$_post["value"]提交的值: 0;insert into admin_users(username,password) values (‘me’,'mypassword’); 那麼當這個查詢發送給mysql查詢的時候,那麼就變成了下面這條sql: update mytable set col1=0; insert into admin_users(username,password) values (‘me’,'mypassword’); where col2=’somevalue’; 這明顯是一個有害的查詢!首先這個查詢會在mytable表裏更新col1。這個並無什麼麻煩的,可是第二個表達式,它將執行insert表達式來插入一個能登錄的新管理員。第三個表達式就廢棄了,但同時sql解析器將拋出一個錯誤,這個有害的查詢才完成。這個攻擊就是你們常說的sql injection(注:sql注入)。 固然,sql injection存在一個問題,對方必須瞭解你的數據庫結構。在這個例子中,攻擊者是知道你有一個表admin_users,而且知道包含username和password字段,同時,存儲的密碼是沒有加密的。 除了你本身,通常的網站訪問者是不知道這些關於數據庫的信息。但是,若是你使用了一個開發源代碼的在線電子商務程序,或者使用一個自由的討論版程序,這些數據表的定義都是已知的,或者有一些用戶可以訪問到你的數據庫。 此外,你的腳本輸出會提示一個查詢錯誤,這些信息裏包含了不少關於數據庫結構的重要信息。在一個正常工做的網站上,你應該考慮設置display_errors選項爲off,而且使用log_errors來代替display_errors,把警告和錯誤信息插入到文件中。 (數據庫權限:它是一個很是重要的東西,你只有正確的權限,才能經過腳本正確的鏈接數據庫。你應該不要在腳本中使用管理員去鏈接數據庫。若是你這麼作,那麼一個攻擊者將可能獲取所有的數據庫權限,而且包括其餘相同服務器的權限。攻擊者將可能運行grant或create user命令來獲取更多的訪問權限。) 若是你要防止sql injection攻擊,你必須保證用戶表單裏提交的內容不是一個可以執行的sql表達式。 前一個例子中,咱們使用一個整型值來進行更新。若是在單引號後面跟上一個字符串,這個攻擊者在分號以前必須提交一個閉合的引用在整個sql表達式中。但是,當magic_quotes_gpc選項是開啓的時候,在web表單中提交的引號將自動被轉義。 爲了防止被惡意的攻擊者進行sql injection攻擊,你應該老是確認提交的數據是合法的。若是你須要的是一個整數值,那麼你可使用is_numeric函數來測試這個表達值,或者使用settype函數來轉換爲一個數字,清除任何一個傻傻的sql語句。 若是你開發的程序須要幾個提交的值在一個sql表達式裏,你可以使用sprintf函數來構建一個sql字符串,使用格式化字符來指示數據類型的每一個值。看下面的例子: $sql=sprintf(「update mytable set col1=%d where col2=’%s’」, $_post["number"], mysql_escape_string($_post["string"])); 在上一個例子中,整個mysql的數據已經被使用,因此這個字符串已經經過mysql_escape_string函數進行過濾。對於其餘數據庫,你可使用addslashes函數進行轉義,或者使用其餘方法。