使用 eval 动态构建关联数组是否安全?

Can using eval to dynamically build an associative array be made secure?

我知道使用 eval 来执行用户输入的字符串是危险的。 From another question, 到目前为止测试,似乎动态初始化关联数组的唯一方法是使用 eval。

考虑以下示例(比如 hash_test.sh),很明显用户输入可用于注入和 运行 任意命令。

#!/bin/bash

key0="a"
value0="b"
key1='c]="d"); echo "You were hacked on $(date)"; #'
value2="2"
input=$(cat - <<EOF
[$key0]="$value0"
[$key1]="$value1"
EOF
)

eval "declare -A hash=( ${input[@]} )"
echo "keys";
for key in "${!hash[@]}"; do
    echo "Key: $key Value: ${hash[$key]}";
done;

运行 hash_test.sh 演示问题。

是否有一种技术可以安全地转义用户输入以确保安全?

首先——链接答案中给出的 eval 与没有它的 declare 的行为是多余的:

string='["key1"]="value1" ["key2"]="value2"'
declare -A assoc_array="($string)"
echo "Value of key1 is ${assoc_array[key1]}"

但是,这确实具有相同的安全风险:

string='["key1"]="$(touch /tmp/i-am-insecure)"'
declare -A assoc_array="($string)"
ls -l /tmp/i-am-insecure ## guess what, it exists

可以 引用 printf %q 生成的值,如果你真的坚持的话:

printf -v string '[%q]=%q' "key1" '$(touch /tmp/i-am-insecure)'
declare -A assoc_array="($string)"
ls -l /tmp/i-am-insecure ## not found!

但最佳做法是迭代填充数组。以完全明确的格式序列化:

for key in "${!array[@]}"; do printf '%s[=13=]' "$key" "${array[$key]}"; done >file

...并从该格式反序列化:

declare -A array
while IFS= read -r -d '' key && IFS= read -r -d '' value; do array[$key]=$value; done <file