如何通过 ssh 安全地 return 一个 bash 数组?

How can I safely return a bash array over ssh?

bashshell中,数组可以很容易地用declare -p引用,然后eval稍后编辑到return它们就正常了。这对于通过 SSH 将数组(作为脚本的一部分)传递到远程计算机似乎是可以接受的。

问题是,我不想期待同样程度的信任。如果远程计算机受到威胁,感染可能会通过未经处理的 eval 语句传播到本地计算机。

目前,为了在机器之间传递数组,我使用如下方法:

#!/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

ssh 会话的输出直接传递给 eval 时,此脚本中的主要不安全因素接近尾声。如何在 bash 中清理此输入?

通用、安全的答案是用 NUL 分隔数组的条目,通过标准输出传递以 NUL 分隔的文字数据,并使用 while read 循环来解释它。

观察:

get_remote_array() {
  local args
  local hostname=; 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[=10=]' "$@" 
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[@]}"

此演示双向传递潜在的恶意数据,并演示它在往返过程中安然无恙。