雖然已是 2018 年,但網上依然流傳著一些「高危 PHP 函數,請一定要禁用!」的標題黨文章(搜索關鍵字:一些需要禁用的PHP危險函數)。
這些文章的內容簡單直接,給出 php.ini
的 disable_functions
的配置(包含一大堆函數),說這些函數十分危險,一定要禁用,有的內容甚至和7、8年前一模一樣,被開發者們奉為秘籍,薪火相傳。
禁用危險函數在理論上是可以加強安全性,但這種做法就好比做飯時害怕用菜刀切菜傷到自己而改用手撕。搞安全一定要重視對入口的控制,而不是自廢武功,因為禁用某些函數會導致某些需求很難、甚至不能實現。
舉個例子。
比如 Laravel
中定時任務功能的底層使用了 Symfony/Process
,其中就依賴 proc_open
函數來執行命令(及其一系列函數),如果被禁用,定時任務就沒法用了。
這里還有個小坑。
朋友本來有一個穩定運行的 Laravel
項目,但某天為了加強安全性,就在 php.ini
里禁用了一堆函數(網上找來的),其中就包含 proc_open
這些。后來他突然發現所有的定時任務都沒有跑了,Laravel
日志和 PHP
錯誤日志也沒有任何異常。后來他猜測應該和函數禁用行為有關,于是還原了配置,可是此時定時任務還是沒有運行。
這里的坑就在于他的所有定時任務都設置了 withoutOverlapping
。當開啟這個設置之后,Laravel
在運行任務時會設置排他鎖:開始的時候檢查有沒有上鎖,有鎖則忽略執行,否則就上鎖,執行命令,執行結束之后解鎖。上鎖當然沒問題,可是執行掛了(這里應該是靜默失敗,普通異常是會被捕捉然后解鎖的),后面就自然沒有解鎖,所以配置恢復之后,開始執行時發現鎖依然存在,是不會實際執行的。
怎么解決呢?Laravel
的鎖使用的系統默認 Cache
,所以只需要去對應 Cache
的 driver 中刪掉鎖的緩存文件就好了,或者等待鎖過期之后也行(5.5
默認是 24 小時)。