命令列注入
問題
與 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
。所有人都必須仔細驗證和轉移他們的輸入。