Shell启动进程存在注入漏洞,如何用Bandit排查并替换commands.getoutput?
Hey there! Let's tackle your questions one by one—since you're new to security, I'll keep things clear and practical.
Shell注入漏洞的核心原因是直接将用户可控的输入拼接进Shell命令中,让Shell解析了恶意输入。修复的关键思路是绕过Shell直接调用进程,或者严格处理输入:
优先选择无Shell的进程调用方式:使用
subprocess模块的列表参数形式,让操作系统直接执行二进制程序,参数独立传递,不会被Shell解析。
比如原来有风险的代码:import subprocess # 危险:用户输入会被Shell解析 subprocess.call("ls " + user_controlled_path, shell=True)修复后:
import subprocess # 安全:参数独立传递,无Shell解析 subprocess.call(["ls", user_controlled_path])如果必须使用Shell特性(如管道、通配符):一定要对用户输入进行严格的转义处理,使用
shlex.quote()来转义所有Shell特殊字符:import subprocess import shlex safe_input = shlex.quote(user_controlled_input) subprocess.call("grep " + safe_input + " logfile.txt | wc -l", shell=True)注意:这种方式只能降低风险,依然不如无Shell的方式安全。
commands库确实存在于Python 2.7中,但它的所有方法(getoutput、getstatusoutput)都是通过Shell执行命令的,天生带有注入风险,官方也推荐用subprocess模块替代:
替代
commands.getoutput(cmd):
如果可以放弃Shell,尽量用无Shell的subprocess.check_output:import subprocess # 无Shell的安全方式(如果cmd不需要Shell特性) output = subprocess.check_output(["echo", "hello"]).strip()如果必须保留Shell(比如需要管道),可以用:
import subprocess output = subprocess.check_output("echo hello | tr 'a-z' 'A-Z'", shell=True, stderr=subprocess.STDOUT).strip()但同样要注意对用户输入做转义处理。
替代
commands.getstatusoutput(cmd):
可以用subprocess.Popen获取返回码和输出:import subprocess proc = subprocess.Popen(["ls", "/invalid/path"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = proc.communicate() return_code = proc.returncode # 类似commands.getstatusoutput的返回格式:(return_code, stdout + stderr) result = (return_code, (stdout + stderr).strip())
Bandit标记commands.getoutput有漏洞,本质是因为这个方法默认通过Shell执行命令。如果你的代码中用它执行的命令包含任何用户可控的输入,攻击者就可以通过输入特殊字符(比如;、|、&&)来拼接恶意命令,比如:
假设代码是
commands.getoutput("echo " + user_input),如果用户输入"; rm -rf /",实际执行的命令会变成echo ; rm -rf /,这会直接执行删除系统文件的恶意操作。
所以不管是commands库还是subprocess用shell=True,只要命令中拼接了未处理的用户输入,都存在注入风险——这也是为什么推荐优先用无Shell的进程调用方式。
内容的提问来源于stack exchange,提问作者kRazzy R




