child_process

中文文档:http://nodejs.cn/api/child_process.html

代码

1.js
用exec 开启一个子进程

  1. const child_process = require('child_process')
  2. const {exec} = child_process
  3. //node.js的回调的特点:第一个参数都是error
  4. exec('ls ./',(error,stdout,stderr)=>{
  5. console.log(error);
  6. console.log(stdout);
  7. console.log(stderr);
  8. })

运行结果
image.png
第一行输出 null 意思是没有错误
第二行开始就是 文件目录 是用户输出的结果(ls ./命令)
最后没有打印stderr 因为执行没有报错。

整个过程是:先执行了exec(‘ls ./‘)这个子进程, 然后再执行后面的回调,打印出了上面这些东西(运行结果)

使用目的

  • 子进程的运行结果储存在系统缓存之中(最大200kb)
  • 等到子进程运行结束以后,主进程再用回调函数读取子进程的运行结果。

API

exec(cmd, options, fn)

  • execute的缩写,用于执行bash命令
  • 同步版本:execSync
  • const res = execSync(‘ls ./‘,()=>{})

  • 返回一个流 ```javascript const streams = exec(‘ls -l ./‘)

streams.stdout.on(‘data’,(chunk)=>{ console.log(chunk); })

  1. 注意exec不是一个stream stdout才是stream
  2. <a name="t7ENl"></a>
  3. ## ![image.png](https://cdn.nlark.com/yuque/0/2020/png/851574/1608189490108-83189771-6397-4bb3-b29f-93e56e3896e5.png#align=left&display=inline&height=144&margin=%5Bobject%20Object%5D&name=image.png&originHeight=144&originWidth=550&size=16806&status=done&style=none&width=550)
  4. <a name="Baewi"></a>
  5. ## Promise
  6. 因为现在是用回调的形式,用promise的话可以避免回调地狱。
  7. - 可以使其promise化(用util.promisify
  8. ```javascript
  9. const child_process = require('child_process')
  10. const util = require('util')
  11. const {exec} = child_process
  12. const exec2 = util.promisify(exec)
  13. exec2('ls ./').then(data => {
  14. console.log(data)
  15. })

image.png

有漏洞

  • 如果cmd被注入了,可能执行意外代码
  • 推荐使用execFile
    1. const exec2 = util.promisify(exec)
    2. const userInput = '. && pwd'
    3. exec2(`ls ./ ${userInput}`).then(data => {
    4. console.log(data.stdout)
    5. })
    image.png
    这样就会执行了 pwd命令
    如果是 rm -rf / 呢? 所以exec是极其危险的。

execFile

  • 执行特定的程序
  • 命令行的参数要用数组形式传入,无法注入
  • 同步版本:execFileSync
  • 支持流
  • 好处就是不会引发注入

1.js

  1. const child_process = require('child_process')
  2. const {execFile} = child_process
  3. const userInput = '. && pwd'
  4. execFile("ls", ['-la',`${userInput}`],(error,stdout)=>{
  5. console.log(error);
  6. console.log(stdout);
  7. })

image.png
运行之后会直接报错,看报错原因:因为execFile接收文件路径,. && pwd 不是文件路径
所以这样就可以防止cmd注入

execFile会通过数组的形式让你传入后面的每一部分,所以你没办法传入一个 ‘&&’

options

是execFile和exec的第二个参数。

options常用的几个值:
cwd:执行的目录
env:环境变量
shell: 用什么shell执行当前命令
maxBuffer:最大缓存(如:1024*1024)

  1. execFile("ls", ['-la',`${userInput}`],{
  2. cwd:'c:\\',
  3. env:{NODE_ENV:'development'},
  4. maxBuffer:1024*1024
  5. }, (error,stdout)=>{
  6. console.log(error);
  7. console.log(stdout);
  8. })