最有效的防护是直接禁用eval;它会导致shell二次解析不可信字符串而引发命令注入,应优先使用${!var}、$(cmd)、函数封装或declare -n等安全替代方案。

直接禁用 eval 是最有效的防护手段。它本质是让 shell 对字符串做第二次解析,一旦字符串含不可信内容,就等于把命令执行权交给了攻击者。动态拼接指令链的需求真实存在,但 eval 不是唯一解,更不是安全解。
优先用安全替代方案代替 eval
多数所谓“必须用 eval”的场景,其实有更可控的写法:
-
间接变量引用:用
${!varname}取值,不用eval echo $$varname -
命令替换:如需执行外部命令结果,用
$(command)或反引号,而非eval "$(command)" - 函数封装:把逻辑拆进函数,用明确参数控制行为,避免拼接字符串再执行
- declare -n(Bash 4.3+):用于变量名间接访问,比 eval 更语义清晰、限制更强
若确需使用 eval,输入必须全程可信且封闭
可信不等于“看起来像用户输的”,而是指:来源固定、格式受控、无任何外部干预可能。例如:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 只从预定义配置文件读取(如
/etc/myapp/conf),且该文件权限为600、属主为 root - 只拼接内部常量或已通过正则严格校验的变量,例如:
[[ $input =~ ^[a-zA-Z0-9_]{1,32}$ ]] || exit 1 - 完全避开用户输入、环境变量、命令行参数、文件内容、网络响应等任何不可信源
绝对禁止的模式(即使用了也等于开门揖盗)
以下写法无论加多少引号或过滤,都不可修复其根本风险:
-
eval "ls $USER_INPUT"—— 即使 $USER_INPUT 被 trim 或去空格,仍可注入$(id)、;$((1+1))等 -
eval "echo ${array[$index]}"—— 若 index 来自用户,数组内容不受控,就等同于执行任意代码 -
eval "$(curl -s https://trusted.site/cmd.sh)"—— “trusted.site” 一旦被劫持或中间人攻击,即失守 - 用
sed、awk替换关键字后再 eval —— 替换逻辑本身可能被绕过,且 eval 仍会二次解析结果
边界过滤不能依赖简单黑名单或字符删除
过滤 ;、|、&、$() 等只是表层防御,攻击者可用如下方式绕过:
- 用
%0a(换行符)替代分号实现命令分隔 - 用
${PATH:5:1}提取字母拼出cat、flag - 用
IFS变量或$'\x20'绕过空格过滤 - 嵌套多层命令替换:
$( $( $(... ) ) )混淆解析层级
真正可靠的边界控制,是根本不让不可信数据进入 eval 的作用域 —— 用白名单限定输入范围,用类型/长度/正则硬约束,再配合调用上下文隔离(如单独用户、最小权限 shell)。










