Apache-2.2
PHP 安全模式/open_basedir - lstat 性能問題
PHP lstat 在讀取文件之前多次查找完整路徑。當在 apache httpd 配置中指定PHP_ADMIN_VALUE open_basedir 設置或 safe_mode 為 ON時,就會發生這種情況。
如果我有一個只有 phpinfo.php 頁面的簡單網站,並且裡面只有“”。
考慮我們有最新版本的 httpd (2.2.15) 和 PHP (5.2.13 或 5.3.2)。
如果我們在虛擬主機配置中指定safe_mode=on 或 PHP_ADMIN_VALUE open_basedir :
<目錄“/usr/local/myspace/webspace/httpdocs”> PHP_ADMIN_VALUE open_basedir "/usr/local/myspace/webspace" </目錄> <虛擬主機 *:80> 伺服器名稱 damorealt.xoom.it DocumentRoot "/usr/local/myspace/webspace/httpdocs" CustomLog /var/log/httpd/damorealt/access_log 結合 ErrorLog/var/log/httpd/damorealt/error_log </虛擬主機>
呼叫頁面http://damorealt.xoom.it/phpinfo.php我們可以重現以下行為:
第一次檢查
25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0
第二次檢查
25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0
第三次檢查(不完整)
25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
第五次檢查。
25933 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 25933 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0
閱讀文件!
25933 打開(“/usr/local/myspace/webspace/httpdocs/phpinfo.php”,O_RDONLY)= 16 25933 fstat(16, {st_mode=S_IFREG|0644, st_size=16, ...}) = 0 25933 讀取(16,“\n”,8192)= 16 25933 讀取(16,“”,8192)= 0 25933 讀取(16,“”,8192)= 0 25933 關閉(16)= 0
如果 PHP_ADMIN_VALUE open_basedir “/usr/local/myspace/webspace” 被刪除 : :
第一次檢查
26235 時間(NULL) = 1278696735 26235 lstat("/usr", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local/myspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local/myspace/webspace", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local/myspace/webspace/httpdocs", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0 26235 lstat("/usr/local/myspace/webspace/httpdocs/phpinfo.php", {st_mode=S_IFREG|0644, st_size=16, ...}) = 0
閱讀文件。
26235 打開(“/usr/local/myspace/webspace/httpdocs/phpinfo.php”,O_RDONLY)= 16 26235 fstat(16, {st_mode=S_IFREG|0644, st_size=16, ...}) = 0 26235 讀取(16,“\n”,8192)= 16 26235 讀取(16,“”,8192)= 0 26235 讀取(16,“”,8192)= 0 26235 關閉(16)= 0 26235 uname({sys="Linux", node="svilpar4", ...}) = 0 26235 時間(NULL) = 1278696735 26235 writev(15, [{"HTTP/1.1 200 OK\r\nDate: Fri, 09 J"..., 173},[...] 26235 chdir("/") = 0
有人能解釋一下為什麼 PHP 會有這樣的行為嗎?
如果設置了 safe_mode 或 open_basedir,則 Realpath 記憶體被禁用。這會顯著降低 PHP 引擎的性能,並且這種行為會使伺服器癱瘓。特別是因為缺乏文件!
查看 PHP 引擎 5.2.13 的原始碼 main/main.c 可以看到:
1292: /* 如果設置了 safe_mode 或 open_basedir,則禁用真實路徑記憶體 */ if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) { CWDG(realpath_cache_size_limit) = 0; } 1769:/*如果設置了safe_mode或open_basedir,則禁用真實路徑記憶體*/ if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) { CWDG(realpath_cache_size_limit) = 0; }