【问题标题】:How can I safely return a bash array over ssh?如何通过 ssh 安全地返回 bash 数组?
【发布时间】:2015-08-08 18:11:06
【问题描述】:

bash shell 中,可以使用declare -p 轻松引用数组,然后稍后使用evaled 将它们恢复正常。对于通过 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 中的此输入?

【问题讨论】:

  • 假设没有预期的模块在其名称中包含换行符是否安全?如果是这样,我就不会费心尝试在任一方向上对数组进行编码;只需使用模块名称的多行列表即可。
  • 顺便说一句,您最好使用&lt;&lt;'EOF' 来逐字传递脚本,并在远程shell 的命令行中逐字传递参数,而不是将它们替换为脚本文本;本地计算机上的数据扩展为远程代码的空间更少。
  • ...我在回答中展示的一种技术。 :)
  • @chepner,当然,这可能是安全的(从安全角度来看肯定是安全的),但是由于没有保证有效数据范围的人可能会重复使用该问题,为什么不这样做是否正确并涵盖了所有有效的 C 字符串?
  • 我不想写一个完全正确的答案(我很确定我会弄错一些细节),所以我只是想提出一个更容易实现的替代方案。另外,我很确定你很快就会提供正确的答案:)

标签: arrays linux bash shell ssh


【解决方案1】:

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

观察:

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[@]}"

此演示在两个方向上传递潜在的恶意数据,并证明它可以在往返过程中安然无恙。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-06
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 2018-09-12
    • 2014-03-29
    • 2010-12-07
    • 2017-03-15
    相关资源
    最近更新 更多