PHP 選項“cgi.fix_pathinfo”對於 Nginx + PHP-FPM 真的很危險嗎?
關於與Nginx 使用的 PHP 選項(通常是 PHP-FPM,快速 CGI)相關的安全問題已經有 很多 討論。
cgi.fix_pathinfo
結果,預設的nginx配置文件習慣說:
# NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini
但是,現在,“官方”Nginx wiki聲明PATH_INFO 可以在不禁用上述 PHP 選項的情況下正確處理。所以呢?
問題
- 你能清楚地解釋一下是做什麼的
cgi.fix_pathinfo
嗎?(官方文件只是說:“有關 PATH_INFO 的更多資訊,請參閱 CGI 規範”)- PHP 將如何處理這些
PATH_INFO
和SCRIPT_FILENAME
變數?- Nginx 為什麼以及如何危險?(詳細例子)
- 這些程序的最新版本中是否仍然存在該問題?
- Apache易受攻擊嗎?
我試圖了解每一步的問題。例如,我不明白為什麼使用 php-fpm Unix 套接字可以避免這個問題。
TL; DR - 修復(您甚至可能不需要)非常簡單,並且在此答案的末尾。
我將嘗試解決您的具體問題,但是您對 PATH_INFO 是什麼的誤解使問題本身有點錯誤。
第一個問題應該是“這個路徑資訊業務是什麼?”
- 路徑資訊是 URI 中腳本之後的內容(應以正斜杠開頭,但在以 a 開頭的查詢參數之前結束
?
)。維基百科關於 CGI的文章概述部分的最後一段很好地總結了它。下面PATH_INFO
是“/THIS/IS/PATH/INFO”:http://example.com/path/to/script.php/THIS/IS/PATH/INFO?query_args=foo
您的下一個問題應該是:“PHP 如何確定什麼
PATH_INFO
和SCRIPT_FILENAME
是什麼?”
- 早期版本的 PHP 很幼稚,從技術上講甚至不支持
PATH_INFO
.,所以應該是PATH_INFO
的SCRIPT_FILENAME
,是的,在很多情況下都被破壞了。我沒有足夠舊的 PHP 版本來測試,但我相信它SCRIPT_FILENAME
在上面的範例中看到了整個 shebang:“/path/to/script.php/THIS/IS/PATH/INFO”(前綴為docroot 像往常一樣)。- 啟用 cgi.fix_pathinfo 後,PHP 現在可以正確找到上述範例的“/THIS/IS/PATH/INFO”,並將其放入
PATH_INFO
並SCRIPT_FILENAME
獲取指向所請求腳本的部分(當然,以 docroot 為前綴)。- 注意:當 PHP 開始真正支持
PATH_INFO
時,他們必須為新功能添加配置設置,以便執行依賴於舊行為的腳本的人可以執行新的 PHP 版本。這就是為什麼它甚至有一個配置開關。它應該從一開始就內置(具有“危險”行為)。但是 PHP 怎麼知道腳本的哪一部分以及它的路徑資訊呢?如果 URI 類似於:
http://example.com/path/to/script.php/THIS/IS/PATH/INFO.php?q=foo
- 在某些環境中,這可能是一個複雜的問題。在 PHP 中發生的情況是,它會找到與伺服器 docroot 下的任何內容都不對應的 URI 路徑的第一部分。對於這個例子,它發現在你的伺服器上你沒有“/docroot/path/to/script.php/THIS”但是你肯定有“/docroot/path/to/script.php”所以現在
SCRIPT_FILENAME
已經下定決心,PATH_INFO
得到剩下的。- 因此,現在 Nginx 文件和Hrvoje Špoljar 的回答(你不能對這樣一個清晰的例子過於挑剔)中詳細描述的危險的好例子變得更加清晰:鑑於 Hrvoje 的例子(“ http://example. com/foo.jpg/nonexistent.php “),PHP 在你的 docroot “/foo.jpg” 上看到一個文件,但它沒有看到任何名為 “/foo.jpg/nonexistent.php” 的文件,所以
SCRIPT_FILENAME
得到 “/foo.jpg” (同樣,以 docroot 為前綴)並PATH_INFO
獲得“/nonexistent.php”。
現在應該清楚它為什麼以及如何造成危險:
- Web 伺服器確實沒有錯 - 它只是將 URI 代理到 PHP,它無辜地發現“foo.jpg”實際上包含 PHP 內容,所以它執行它(現在你已經被 pwned 了!)。這並不是Nginx 本身所特有的。
真正的問題是你讓不受信任的內容上傳到某個地方而不進行清理,並且你允許其他任意請求到同一位置,PHP 會在可能的情況下愉快地執行。
可以建構或配置 Nginx 和 Apache 以防止使用此技巧的請求,並且有很多範例說明如何做到這一點,包括在user2372674 的答案中。這篇部落格文章很好地解釋了這個問題,但它缺少正確的解決方案。
但是,最好的解決方案是確保 PHP-FPM 配置正確,這樣它就永遠不會執行文件,除非它以“.php”結尾。值得注意的是,最新版本的 PHP-FPM (~5.3.9+?) 將其作為預設設置,因此這種危險不再是太大的問題。
解決方案
如果您有最新版本的 PHP-FPM(~5.3.9+?),那麼您無需執行任何操作,因為下面的安全行為已經是預設設置。
否則,找到 php-fpm 的
www.conf
文件(也許/etc/php-fpm.d/www.conf
,取決於你的系統)。確保你有這個:security.limit_extensions = .php
同樣,這在當今許多地方都是預設設置。
請注意,這並不能阻止攻擊者將“.php”文件上傳到 WordPress 上傳文件夾並使用相同的技術執行該文件。您仍然需要為您的應用程序提供良好的安全性。