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.
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.
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
?
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.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.