安全地将参数传递给通过su执行的命令

时间:2015-10-06 09:40:32

标签: bash security

使用sudo,可以作为其他用户执行命令,真的安全地将参数传递给该命令。

示例讨厌的论点:

nastyArg='"double quoted" `whoami` $(whoami) '"'simple quoted "'$(whoami)'"'"

预期输出,通过termninal运行为congelli501:

 % echo "$nastyArg"
"double quoted" `whoami` $(whoami) 'simple quoted $(whoami)'

通过sudo执行为congelli501:

 # sudo -u congelli501 -- echo "$nastyArg"
"double quoted" `whoami` $(whoami) 'simple quoted $(whoami)'

执行为congelli501,通过su(通常的转义方法):

 # su congelli501 -c "echo '$nastyArg'"
"double quoted" `whoami` $(whoami) simple quoted congelli501

正如您所看到的,该参数未被安全传递,因为它被shell重新解释。

有没有办法通过su启动命令并直接传递其参数,就像使用sudo一样?

2 个答案:

答案 0 :(得分:1)

将命令作为su中的shell脚本参数传递似乎有效:

 # su congelli501 -s "$(which echo)" -- "$nastyArg" "'another arg'"
"double quoted" `whoami` $(whoami) 'simple quoted $(whoami)' 'another arg'

使用示例:

# Safely execute a command as an other user, via su
#
#  $1 -> username
#  $2 -> program to run
#  $3 .. n -> arguments
function execAs() {
    user="$1"; shift
    cmd="$1"; shift
    su "$user" -s "$(which "$cmd")" -- "$@"
}

execAs congelli501 echo "$nastyArg" "'another arg'"

答案 1 :(得分:1)

这里的根本问题是你试图嵌套引号。您希望将su -c "stuff "with" double "quotes"解析为|su||-c||stuff "with" double "quotes"|,但它实际上会被解析为|su||-c|,{{1 }},|stuff ||with|| double|但是最后四个标记在评估后粘贴在一起作为一个字符串(请注意"内部"引号终止的空格表面上的"外部"引用而不是包裹在其中。)

在双引号内,{<1}}在任何内容传递给|quotes|之前由shell 扩展。

你可以做的是(a)`whoami`(几乎注定失败)或(b)定义的值周围添加更多引号它在su执行的shell的上下文中。另一个不同的选择是(c)以一种解除它的方式传递值,例如在标准输入上。

$nastyArg

这可能看起来过于简单化了,但是当你对su以某种方式可能评估的内容没有完全信任时,这真的是可行的方法。

这是printf '%s\n' "$nastyArg" | su -c 'cat' congelli501 优于root的原因之一。