express 集成命令行工具

以下是在 Express 应用中集成命令行工具的完整实现方案,涵盖安全执行、异步处理和实时反馈等功能:

基础实现(安全版)

const express = require('express')
const { exec } = require('child_process')
const { promisify } = require('util')
const execAsync = promisify(exec)
const app = express()
const PORT = 3000

// 安全执行中间件
const validateInput = (req, res, next) => {
  if (!/^[a-zA-Z0-9-_]+$/.test(req.params.command)) {
    return res.status(400).json({ error: 'Invalid command format' })
  }
  next()
}

app.get('/cmd/:command', validateInput, async (req, res) => {
  try {
    const { stdout, stderr } = await execAsync(req.params.command, {
      timeout: 5000,
      env: { PATH: process.env.PATH }
    })
    
    res.json({
      status: 'success',
      output: stdout,
      warnings: stderr
    })
  } catch (error) {
    res.status(500).json({
      status: 'error',
      error: error.message,
      code: error.code
    })
  }
})

app.listen(PORT, () => {
  console.log(`Server running on port ${PORT}`)
})

高级功能实现

1. 实时流式输出

const { spawn } = require('child_process')

app.get('/stream/:command', validateInput, (req, res) => {
  res.setHeader('Content-Type', 'text/plain')
  res.setHeader('Transfer-Encoding', 'chunked')

  const child = spawn(req.params.command, [], {
    shell: true,
    env: process.env
  })

  child.stdout.on('data', (data) => {
    res.write(`STDOUT: ${data}`)
  })

  child.stderr.on('data', (data) => {
    res.write(`STDERR: ${data}`)
  })

  child.on('close', (code) => {
    res.end(`\nProcess exited with code ${code}`)
  })
})

2. 后台任务队列

安装所需依赖:

npm install bull express-basic-auth
const Queue = require('bull')
const basicAuth = require('express-basic-auth')
const taskQueue = new Queue('cli-tasks', 'redis://127.0.0.1:6379')

// 认证中间件
const authMiddleware = basicAuth({
  users: { 'admin': 'supersecret' },
  challenge: true
})

app.post('/task', authMiddleware, async (req, res) => {
  const job = await taskQueue.add({
    command: req.body.command,
    params: req.body.args
  }, {
    attempts: 3,
    backoff: { type: 'exponential' }
  })
  
  res.json({ jobId: job.id })
})

// 任务处理器
taskQueue.process(async (job) => {
  const { command, params } = job.data
  return new Promise((resolve, reject) => {
    const child = spawn(command, params, { stdio: 'pipe' })
    let output = ''
    
    child.stdout.on('data', (data) => output += data)
    child.on('close', (code) => {
      code === 0 ? resolve(output) : reject(new Error(`Exit code ${code}`))
    })
  })
})

安全增强措施

  1. 白名单命令控制
const ALLOWED_COMMANDS = {
  'system-info': 'uname -a',
  'network-check': 'ping -c 4 8.8.8.8'
}

app.get('/safe-cmd/:command', (req, res) => {
  const validCommand = ALLOWED_COMMANDS[req.params.command]
  if (!validCommand) {
    return res.status(400).send('Invalid command')
  }

  exec(validCommand, (error, stdout) => {
    if (error) return res.status(500).send(error.message)
    res.type('text/plain').send(stdout)
  })
})
  1. Docker 容器化执行(需安装 Docker SDK)
const Docker = require('dockerode')
const docker = new Docker()

app.post('/docker', async (req, res) => {
  try {
    const container = await docker.createContainer({
      Image: 'alpine',
      Cmd: ['echo', 'safe execution'],
      AttachStdout: true
    })
    
    await container.start()
    const output = await container.logs({ stdout: true, stderr: true })
    await container.remove()
    
    res.send(output.toString())
  } catch (error) {
    res.status(500).send(error.message)
  }
})

监控与日志

const { createLogger, transports } = require('winston')
const logger = createLogger({
  transports: [new transports.File({ filename: 'command.log' })]
})

app.use((req, res, next) => {
  if (req.path.includes('/cmd/')) {
    logger.info({
      timestamp: new Date(),
      command: req.params.command,
      ip: req.ip
    })
  }
  next()
})

最佳实践建议

  1. 权限控制:
const sudo = require('sudo-prompt')
app.post('/admin-cmd', authMiddleware, (req, res) => {
  sudo.exec(req.body.command, { name: 'MyApp' }, (error, stdout) => {
    if (error) return res.status(500).send(error.message)
    res.send(stdout)
  })
})
  1. 资源限制:
const execOpts = {
  timeout: 10000,
  maxBuffer: 1024 * 1024, // 1MB
  killSignal: 'SIGTERM'
}
  1. 输入验证强化:
const validateComplex = (input) => {
  return !/[;&|><]/.test(input) && 
         input.length < 50 &&
         !/\b(rm|shutdown|halt)\b/.test(input)
}

完整方案整合了以下关键要素:

  • 多层级安全控制(白名单、输入验证、容器化隔离)
  • 多种执行模式(同步、异步、流式)
  • 企业级功能(队列管理、权限控制、日志审计)
  • 资源管理(超时控制、内存限制)
  • 错误处理(重试机制、友好错误提示)

部署时建议配合:

  1. 反向代理(Nginx)
  2. 进程管理(PM2)
  3. 监控系统(Prometheus + Grafana)
  4. 防火墙规则(限制访问IP)

根据实际需求选择适当的安全级别,生产环境建议至少使用白名单+容器化执行的组合方案。

posted @ 2025-03-14 16:17  jintaonote  阅读(42)  评论(0)    收藏  举报