使用 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
我知道使用 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