【问题标题】:How to check if input is Linux shell command or normal text message in Nodejs?如何检查输入是Linux shell命令还是Nodejs中的普通文本消息?
【发布时间】:2019-08-10 03:10:35
【问题描述】:

在 Node.js 中,是否有任何值可以验证文本消息是 linux shell 命令还是普通消息,有/没有实际执行文本? 请提出任何建议。

【问题讨论】:

  • 你是在linux上运行还是多平台?
  • 在 windows 上,在 nodejs 环境中,我需要确认文本是否是 linux 命令...@HagaiWild
  • 你需要保存一个 linux 命令列表ss64.com/bash。然后检查第一个单词是否在该列表中,后面的只是命令的参数(可能有效,也可能无效)。
  • 这似乎是一个很长的方法来创建一个列表并将所有命令保存在一个数据结构中。有什么捷径可以解决吗?
  • 这其实是最简单的。

标签: node.js linux shell command sanitization


【解决方案1】:
var commnads = 'alias,apt-get,aptitude,aspell,awk,basename,bc,bg,bind,break,builtin,bzip2,cal,case,cat,cd,cfdisk,chattr,chgrp,chmod,chown,chroot,chkconfig,cksum,cmp,comm,command,continue,cp,cron,crontab,csplit,curl,cut,date,dc,dd,ddrescue,declare,df,diff,diff3,dig,dir,dircolors,dirname,dirs,dmesg,du,echo,egrep,eject,enable,env,eval,exec,exit,expect,expand,export,expr,false,fdformat,fdisk,fg,fgrep,file,find,fmt,fold,for,fsck,ftp,function,fuser,gawk,getopts,grep,groupadd,groupdel,groupmod,groups,gzip,hash,head,history,hostname,htop,iconv,id,if,ifconfig,ifdown,ifup,import,install,iostat,ip,jobs,join,kill,killall,less,let,link,ln,local,locate,logname,logout,look,lpc,lpr,lprm,lsattr,lsblk,ls,lsof,lspci,man,mkdir,mkfifo,mkfile,mknod,mktemp,more,most,mount,mtools,mtr,mv,mmv,nc,netstat,nft,nice,nl,nohup,notify-send,nslookup,open,op,passwd,paste,Perf,ping,pgrep,pkill,popd,pr,printenv,printf,ps,pushd,pv,pwd,quota,quotacheck,ram,rar,rcp,read,readonly,rename,return,rev,rm,rmdir,rsync,screen,scp,sdiff,sed,select,seq,set,shift,shopt,shutdown,sleep,slocate,sort,source,split,ss,ssh,stat,strace,su,sudo,sum,suspend,sync,tail,tar,tee,test,time,timeout,times,touch,top,tput,traceroute,trap,tr,true,tsort,tty,type,ulimit,umask,unalias,uname,unexpand,uniq,units,unrar,unset,unshar,until,useradd,userdel,usermod,users,uuencode,uudecode,vi,vmstat,w,wait,watch,wc,whereis,which,while,who,whoami,write,xargs,xdg-open,xz,yes,zip,.,!!,###'.split(',');

if (commands.some(command => text_to_check.startsWith(command + ' ')))
{
    //code goes here
}

【讨论】:

  • </etc/password foo=bar "a"\w\k '{print ENVIRON["foo"],$0;exit}'
  • /bin/echo does not start with echo; ${E:+}e${C:+}h${H:+}h${O:+}o hello
  • @jhnc 如果从 Windows 运行。无法保证所谓的 linux 环境中的文件夹会是什么样子。也许可以假定直接位于根文件夹(例如 /bin)的文件夹,但不能假定其他文件夹。
  • 确实如此。但问题是测试一个字符串是否是一个有效的 shell 命令,而不是检查一个特定的 shell 命令是否会在某些特定的机器上执行。
【解决方案2】:

shell 的type 命令会检测内置命令、别名、函数、外部命令等。

child_process = require('child_process')

['lua','foobar'].forEach((cmd) => {
  result = child_process.spawnSync('sh', ['-c', `type ${cmd}`])
  console.log(result.status + '\t' + result.stdout.toString())
})
0       lua is /usr/local/bin/lua

127     foobar: not found

确实,恶意输入还是恶意的。

这是一种解决方法:在 type cmd 字符串中引用命令,但您必须处理命令本身中的任何引号

// 1. shell-quote any single quotes in the cmd
cmd = "da$(echo 'hello world')te";      // 'da$(echo \'hello world\')te'
escaped = cmd.replace(/'/g, `'"'"'`);   // 'da$(echo \'"\'"\'hello world\'"\'"\')te'
// 2. in the command string, quote the escaped cmd argument
result = child_process.spawnSync('sh', ['-c', `type '${escaped}'`]);
// .................................................^..........^
console.log(result.status, result.stdout.toString());
127 'da$(echo \'hello world\')te: not found\n'

而且,要合并@dee 的答案,要找到 command 词,您首先必须解析出任何前导变量分配和/或重定向 (https://www.gnu.org/software/bash/manual/bashref.html#Simple-Command-Expansion) 和/或前导打开括号或大括号和/或...基本上实现了一个 sh 解析器。

【讨论】:

  • 这可能还不能执行一些东西:da$(echo>/etc/passwd)te ?
【解决方案3】:

这看起来完全是错误的设计。 在一般情况下,Linux 命令可以是 PATH 中的任何二进制文件、内置 shell 或别名。

您可以检查第一个单词是否指向路径中的二进制文件,但这仍然不能解决 shell 别名或内置插件(您至少需要一个内置插件列表)。

如果有人输入的“文本消息”恰好以一个常用词开头,该词也是一个 Linux 命令(echo、cat、...)?

简短回答:不要这样做,否则后果自负。

【讨论】:

  • 命令不必是第一个单词:重定向和变量赋值可以在它之前,例如
猜你喜欢
  • 2016-05-25
  • 1970-01-01
  • 1970-01-01
  • 2012-06-30
  • 2011-01-28
  • 2010-09-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多