PHP安全模式safe_mode的說明

來源:互聯網
上載者:User

開啟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(關閉安全模式)


 

安全模式配置指令:
名稱 預設值 可修改範圍 更新記錄
safe_mode "0" PHP_INI_SYSTEM
safe_mode_gid "0" PHP_INI_SYSTEM 自 PHP 4.1.0 起可用
safe_mode_include_dir NULL PHP_INI_SYSTEM 自 PHP 4.1.0 起可用
safe_mode_exec_dir "" PHP_INI_SYSTEM
safe_mode_allowed_env_vars "PHP_" PHP_INI_SYSTEM
safe_mode_protected_env_vars "LD_LIBRARY_PATH" PHP_INI_SYSTEM
open_basedir NULL PHP_INI_SYSTEM
disable_functions "" 僅 php.ini 自 PHP 4.0.1 起可用
disable_classes "" 僅 php.ini 自 PHP 4.3.2 起可用

當安全模式開啟的時候,以下函數列表的功能將會受到限制:

函數名 限制
dbmopen() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。
dbase_open() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。
filepro() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。
filepro_rowcount() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。
filepro_retrieve() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。
ifx_* sql_safe_mode 限制, (!= safe mode)
ingres_* sql_safe_mode 限制, (!= safe mode)
mysql_* sql_safe_mode 限制, (!= safe mode)
pg_loimport() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。
posix_mkfifo() 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。
putenv() 遵循 ini 設定的 safe_mode_protected_env_vars 和 safe_mode_allowed_env_vars 選項。請參考 putenv() 函數的有關文檔。
move_uploaded_file() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。
chdir() 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。
dl() 本函數在安全模式下被禁用。
backtick operator 本函數在安全模式下被禁用。
shell_exec()(在功能上和 backticks 函數相同) 本函數在安全模式下被禁用。
exec() 只能在 safe_mode_exec_dir 設定的目錄下進行執行操作。基於某些原因,目前不能在可執行對象的路徑中使用 ..。escapeshellcmd() 將被作用於此函數的參數上。
system() 只能在 safe_mode_exec_dir 設定的目錄下進行執行操作。基於某些原因,目前不能在可執行對象的路徑中使用 ..。escapeshellcmd() 將被作用於此函數的參數上。
passthru() 只能在 safe_mode_exec_dir 設定的目錄下進行執行操作。基於某些原因,目前不能在可執行對象的路徑中使用 ..。escapeshellcmd() 將被作用於此函數的參數上。
popen() 只能在 safe_mode_exec_dir 設定的目錄下進行執行操作。基於某些原因,目前不能在可執行對象的路徑中使用 ..。escapeshellcmd() 將被作用於此函數的參數上。
fopen() 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。
mkdir() 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。
rmdir() 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。
rename() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。
unlink() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。
copy() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (on source and target)
chgrp() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。
chown() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。
chmod() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 另外,不能設定 SUID、SGID 和 sticky bits
touch() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。
symlink() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (注意:僅測試 target)
link() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (注意:僅測試 target)
apache_request_headers() 在安全模式下,以“authorization”(區分大小寫)開頭的標題將不會被返回。
header() 在安全模式下,如果設定了 WWW-Authenticate,當前指令碼的 uid 將被添加到該標題的 realm 部分。
PHP_AUTH 變數 在安全模式下,變數 PHP_AUTH_USERPHP_AUTH_PW 和 PHP_AUTH_TYPE 在 $_SERVER 中不可用。但無論如何,您仍然可以使用 REMOTE_USER 來擷取使用者名稱稱(USER)。(注意:僅 PHP 4.3.0 以後有效)
highlight_file(), show_source() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (注意,僅在 4.2.1 版本後有效)
parse_ini_file() 檢查被操作的檔案或目錄是否與正在執行的指令碼有相同的 UID(所有者)。 檢查被操作的目錄是否與正在執行的指令碼有相同的 UID(所有者)。 (注意,僅在 4.2.1 版本後有效)
set_time_limit() 在安全模式下不起作用。
max_execution_time 在安全模式下不起作用。
mail() 在安全模式下,第五個參數被屏蔽。(注意,僅自 PHP 4.2.3 起受影響)

同樣的,一些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也將被忽略。


安全模式後的影響:
當函數在訪問檔案系統的時候將進行檔案所有者的檢查。預設情況下,會檢查該檔案所有者的使用者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的安全。

1、[隱藏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指令碼引擎的依賴,增強效能。)

2、[檔案系統安全]

安全模式限制了指令碼所有者只能訪問屬於自己的檔案,但是你可以使用open_basedir選現來指定一個你必須訪問的目錄。如果你指定了一個目錄,php將拒絕訪問除了該目錄和該目錄子目錄的其他目錄。open_basedir選項能夠工作在安全模式之外。

限制檔案系統只能訪問/tmp目錄,那麼設定選項為:

open_basedir=/tmp

3、[函數存取控制]

你能夠在disable_functions選項中使用逗號分割來設定函數名,那麼這些函數將在php指令碼中被關閉。這個設定能夠工作在安全模式之外。

disable_functions=dl

當然,同樣的你能夠使用disable_classes選項來關閉對一些類的訪問。

4、[資料庫安全]

假設你的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函數進行轉義,或者使用其他方法

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.