命令列注入
問題
與 SQL 注入允許攻擊者在資料庫上執行任意查詢的方式類似,命令列注入允許某人在 Web 伺服器上執行不受信任的系統命令。使用不正確安全的伺服器,這將使攻擊者完全控制系統。
例如,假設指令碼允許使用者在 Web 伺服器上列出目錄內容。
<pre>
<?php system('ls ' . $_GET['path']); ?>
</pre>
(在實際應用程式中,可以使用 PHP 的內建函式或物件來獲取路徑內容。此示例用於簡單的安全演示。)
人們希望得到一個類似於/tmp 的 path 引數。但是,如果允許任何輸入,path 可能是 ; rm -fr /。然後,Web 伺服器將執行該命令
ls; rm -fr /
並嘗試從伺服器的根目錄中刪除所有檔案。
解
必須使用 escapeshellarg() 或 escapeshellcmd() 轉義所有命令引數。這使得引數不可執行。對於每個引數,還應驗證輸入值。
在最簡單的情況下,我們可以保證我們的例子
<pre>
<?php system('ls ' . escapeshellarg($_GET['path'])); ?>
</pre>
在上一個嘗試刪除檔案的示例之後,執行的命令變為
ls '; rm -fr /'
字串只是作為引數傳遞給 ls,而不是終止 ls 命令並執行 rm。
應該注意的是,上面的示例現在對命令注入是安全的,但不是來自目錄遍歷。要解決此問題,應檢查規範化路徑是否以所需的子目錄開頭。
PHP 提供了各種執行系統命令的功能,包括 exec,passthru,proc_open,shell_exec 和 system。所有人都必須仔細驗證和轉移他們的輸入。