是的,不仅
(( dict[$var]++ ))
不适用于$var 的某些值,但它也是一个任意命令执行漏洞。
bash-5.1$ var='1$(uname>&2)'
bash-5.1$ typeset -A dict
bash-5.1$ (( dict[$var]++ ))
Linux
Linux
用printf %q 或${var@Q} 引用$var 的值不是一个选项,因为对于$var 的某些值,这些运算符使用$'...' 的引用形式,这在算术表达式中是无法理解的:
bash-5.1$ typeset -A dict
bash-5.1$ var=$(seq 2)
bash-5.1$ (( dict[${var@Q}]++ ))
bash-5.1$ echo "${!dict[@]}"
$1\n2
bash-5.1$ var=$'\n\'$(uname >&2)],x['
bash-5.1$ (( dict["${var@Q}"]++ ))
Linux
bash: ((: dict[$'\n\'$(uname >&2)],x[']++ : bad array subscript (error token is "x[']++ ")
(仍然是 ACE)。
使用新的(自 5.0 起)assoc_expand_once 无济于事,因为它仍然无法解决 @/* 值或 ] 字符的问题(因此无法修复ACE 漏洞):
bash-5.1$ shopt -s assoc_expand_once
bash-5.1$ var='x],b[1$(uname>&2)'
bash-5.1$ typeset -A dict
bash-5.1$ (( dict[$var]++ ))
Linux
bash(不是ksh93 也不是zsh)特有的另一个问题是 bash 关联数组不支持空键,因此您不能使用任意字符串作为关联数组键。一种解决方法是使用固定字符串为所有键添加前缀/后缀。
在这里,你可以做到:
dict[.$var]=$(( ${dict[.$var]} + 1 ))
或者(假设assoc_expand_once 选项未启用):
let 'dict[.$var]++'
(确保使用单引号)。
这里使用.作为前缀。
请参阅 How to use associative arrays safely inside arithmetic expressions? 了解所有血腥细节和更多警告。
更一般地说,shell 算术表达式是一个雷区。另见:Security Implications of using unsanitized data in Shell Arithmetic evaluation。