In the bash
shell, arrays can be easily quoted with declare -p
, then eval
ed later to return them to normal. This seems acceptable for passing an array (as part of a script) to a remote machine over SSH.
在bash shell中,可以很容易地用declare -p引用数组,然后再调用数组以将它们返回正常。对于通过SSH将数组(作为脚本的一部分)传递到远程机器,这似乎是可以接受的。
The problem is, going the other way across the wire I don't want to expect the same level of trust. If the remote machine was compromised, an infection could spread to the local machine through unsanitised eval
statements.
问题是,反过来说,我不想期望同样程度的信任。如果远程机器被破坏,感染可能通过未消毒的eval语句传播到本地机器。
Currently, to pass arrays between machines I use an approach like this:
目前,为了在机器之间传递数组,我使用如下方法:
#!/bin/bash
# Define the modules we expect to find installed on the remote machine
expected_modules=(foo-module bar 'baz 2.0')
# SSH into the remote machine, send the arrays back and forth with "declare -p"
unparsed_missing_modules=$(ssh remote-machine /bin/bash << EOF
check_for_module() {
# Placeholder so that this can be tested locally
case \$1 in
foo*) true;;
*) false;;
esac
}
$(declare -p expected_modules)
missing_modules=()
for module in "\${expected_modules[@]}"; do
if ! check_for_module "\$module"; then
missing_modules+=( "\$module" )
fi
done
declare -p missing_modules
EOF
)
# Unpack the result (this is what I want to find an alternative to)
eval "$unparsed_missing_modules"
# Do something with the result after unpacking into an array
for module in "${missing_modules[@]}"; do
echo "Warning: Remote machine is missing $module" >&2
done
The primary insecurity in this script is near the end, when the output of a ssh
session is passed directly to eval
. How can I sanitise this input in bash
?
当ssh会话的输出直接传递给eval时,该脚本的主要不安全性就接近尾声。如何在bash中对输入进行消毒?
1 个解决方案
#1
4
The generic, safe answer is to NUL-delimit your array's entries, pass the literal NUL-delimited data over stdout, and use a while read
loop to interpret it.
通用的、安全的答案是空分隔数组的条目,将文本空分隔的数据传递给stdout,并使用while read循环来解释它。
Observe:
观察:
get_remote_array() {
local args
local hostname=$1; shift
printf -v args '%q ' "$@"
ssh "$hostname" "bash -s $args" <<'EOF'
# in real-world use, print something more useful than the arguments we were started with
# ...but for here, this demonstrates the point:
printf '%s\0' "$@"
EOF
}
array=( )
while IFS= read -r -d ''; do
array+=( "$REPLY" )
done < <(get_remote_array "localhost" \
$'I\ncontain\nnewlines' \
'I want to $(touch /tmp/security-fail)' \
"'"'I REALLY want to $(touch /tmp/security-fail), even in single quotes'"'")
echo "---- Shell-escaped content"
printf '%q\n' "${array[@]}"
echo "---- Unescaped content"
printf '<<%s>>\n' "${array[@]}"
This demonstration passes potentially malicious data in both directions, and demonstrates that it survives the round-trip unharmed.
此演示向两个方向传递潜在的恶意数据,并演示它在往返过程中安然无恙。
#1
4
The generic, safe answer is to NUL-delimit your array's entries, pass the literal NUL-delimited data over stdout, and use a while read
loop to interpret it.
通用的、安全的答案是空分隔数组的条目,将文本空分隔的数据传递给stdout,并使用while read循环来解释它。
Observe:
观察:
get_remote_array() {
local args
local hostname=$1; shift
printf -v args '%q ' "$@"
ssh "$hostname" "bash -s $args" <<'EOF'
# in real-world use, print something more useful than the arguments we were started with
# ...but for here, this demonstrates the point:
printf '%s\0' "$@"
EOF
}
array=( )
while IFS= read -r -d ''; do
array+=( "$REPLY" )
done < <(get_remote_array "localhost" \
$'I\ncontain\nnewlines' \
'I want to $(touch /tmp/security-fail)' \
"'"'I REALLY want to $(touch /tmp/security-fail), even in single quotes'"'")
echo "---- Shell-escaped content"
printf '%q\n' "${array[@]}"
echo "---- Unescaped content"
printf '<<%s>>\n' "${array[@]}"
This demonstration passes potentially malicious data in both directions, and demonstrates that it survives the round-trip unharmed.
此演示向两个方向传递潜在的恶意数据,并演示它在往返过程中安然无恙。