Node.js中安全調(diào)用系統(tǒng)命令的方法(避免注入安全漏洞)
在這篇文章中,我們將學(xué)習(xí)正確使用Node.js調(diào)用系統(tǒng)命令的方法,以避免常見的命令行注入漏洞。
我們經(jīng)常使用的調(diào)用命令的方法是最簡(jiǎn)單的child_process.exec。它有很一個(gè)簡(jiǎn)單的使用模式;通過(guò)傳入一段字符串命令,并把一個(gè)錯(cuò)誤或命令處理結(jié)果回傳至回調(diào)函數(shù)中。
這里是你通過(guò)child_process.exec調(diào)用系統(tǒng)命令一個(gè)非常典型的例子。
child_process.exec('ls', function (err, data) {
console.log(data);
});
不過(guò),當(dāng)你需要在你調(diào)用的命令中添加一些用戶輸入的參數(shù)時(shí),會(huì)發(fā)生什么?顯而易見的解決方案是把用戶輸入直接和您的命令進(jìn)行字符串合并。但是,我多年的經(jīng)驗(yàn)告訴我:當(dāng)你將連接的字符串從一個(gè)系統(tǒng)發(fā)送到另一個(gè)系統(tǒng)時(shí),總有一天會(huì)出問(wèn)題。
var path = "user input";
child_process.exec('ls -l ' + path, function (err, data) {
console.log(data);
});
為什么連接字符串會(huì)出問(wèn)題?
嗯,因?yàn)樵赾hild_process.exec引擎下,將調(diào)用執(zhí)行"/bin/sh"。而不是目標(biāo)程序。已發(fā)送的命令只是被傳遞給一個(gè)新的"/bin/ sh'進(jìn)程來(lái)執(zhí)行shell。 child_process.exec的名字有一定誤導(dǎo)性 - 這是一個(gè)bash的解釋器,而不是啟動(dòng)一個(gè)程序。這意味著,所有的shell字符可能會(huì)產(chǎn)生毀滅性的后果,如果直接執(zhí)行用戶輸入的參數(shù)。
[pid 25170] execve("/bin/sh", ["/bin/sh", "-c", "ls -l user input"], [/* 16 vars */]
比如,攻擊者可以使用一個(gè)分號(hào)";"來(lái)結(jié)束命令,并開始一個(gè)新的調(diào)用,他們可以使用反引號(hào)或$()來(lái)運(yùn)行子命令。還有很多潛在的濫用。
那么什么是正確的調(diào)用方式?
execFile / spawn
像spawn和execFile采用一個(gè)額外的數(shù)組參數(shù),不是一個(gè)shell環(huán)境下可以執(zhí)行其他命令的參數(shù),并不會(huì)運(yùn)行額外的命令。
讓我們使用的execFile和spawn修改一下之前的例子,看看系統(tǒng)調(diào)用有何不同,以及為什么它不容易受到命令注入。
child_process.execFile
var child_process = require('child_process');
var path = "."
child_process.execFile('/bin/ls', ['-l', path], function (err, result) {
console.log(result)
});
運(yùn)行的系統(tǒng)調(diào)用
[pid 25565] execve("/bin/ls", ["/bin/ls", "-l", "."], [/* 16 vars */]
child_process.spawn
使用 spawn 替換的例子很相似。
var child_process = require('child_process');
var path = "."
var ls = child_process.spawn('/bin/ls', ['-l', path])
ls.stdout.on('data', function (data) {
console.log(data.toString());
});
運(yùn)行的系統(tǒng)調(diào)用
[pid 26883] execve("/bin/ls", ["/bin/ls", "-l", "."], [/* 16 vars */
當(dāng)使用spawn或execfile時(shí),我們的目標(biāo)是只執(zhí)行一個(gè)命令(參數(shù))。這意味著用戶不能運(yùn)行注入的命令,因?yàn)?bin/ls并不知道如何處理反引號(hào)或pipe或;。它的/bin/bash將要解釋的是那些命令的參數(shù)。它類似于使用將參數(shù)傳入SQL查詢(parameter),如果你熟悉的話。
但還需要警告的是:使用spawn或execFile并不總是安全的。例如,運(yùn)行 /bin/find,并傳入用戶輸入?yún)?shù)仍有可能導(dǎo)致系統(tǒng)被攻陷。 find命令有一些選項(xiàng),允許讀/寫任意文件。
所以,這里有一些關(guān)于Node.js運(yùn)行系統(tǒng)命令的指導(dǎo)建議:
避免使用child_process.exec,當(dāng)需要包含用戶輸入的參數(shù)時(shí)更是如此,請(qǐng)牢記。
盡量避免讓用戶傳入?yún)?shù),使用選擇項(xiàng)比讓用戶直接輸入字符串要好得多。
如果你必須允許用戶輸入?yún)?shù),請(qǐng)廣泛參考該命令的參數(shù),確定哪些選項(xiàng)是安全的,并建立一個(gè)白名單。
相關(guān)文章
window10下node使用管理神器NVM安裝配置超詳細(xì)步驟
nvm全稱Node Version Manager是 Nodejs 版本管理器,它讓我們能方便的對(duì) Nodejs 的版本進(jìn)行切換,nvm 的官方版本只支持 Linux 和 Mac, Windows 用戶,可以用 nvm-windows,這篇文章主要介紹了window10下node使用管理神器NVM安裝配置超詳細(xì)步驟,需要的朋友可以參考下2023-01-01使用PM2實(shí)現(xiàn)高效的應(yīng)用監(jiān)控與管理功能
PM2?是一個(gè)流行的進(jìn)程管理器,用于?Node.js?應(yīng)用程序,它支持應(yīng)用程序的負(fù)載均衡、自動(dòng)重啟、日志管理、監(jiān)控以及多環(huán)境管理等功能,本文給大家介紹了如何使用PM2實(shí)現(xiàn)高效的應(yīng)用監(jiān)控與管理功能,需要的朋友可以參考下2024-02-02Nest.js參數(shù)校驗(yàn)和自定義返回?cái)?shù)據(jù)格式詳解
這篇文章主要給大家介紹了關(guān)于Nest.js參數(shù)校驗(yàn)和自定義返回?cái)?shù)據(jù)格式的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03基于NodeJS開發(fā)釘釘回調(diào)接口實(shí)現(xiàn)AES-CBC加解密
這篇文章主要介紹了基于NodeJS開發(fā)釘釘回調(diào)接口 實(shí)現(xiàn)AES-CBC加解密,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08詳解Nodejs get獲取遠(yuǎn)程服務(wù)器接口數(shù)據(jù)
這篇文章主要介紹了Nodejs get獲取遠(yuǎn)程服務(wù)器接口數(shù)據(jù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03node.js中的fs.fchown方法使用說(shuō)明
這篇文章主要介紹了node.js中的fs.fchown方法使用說(shuō)明,本文介紹了fs.fchown方法說(shuō)明、語(yǔ)法、接收參數(shù)、使用實(shí)例和實(shí)現(xiàn)源碼,需要的朋友可以參考下2014-12-12