shell注入防护核心是隔离输入与命令执行上下文:用显式参数分隔(如ls -l -- "$input")、数组传参、白名单过滤(仅允许a-za-z0-9_-等)、路径限制(禁..和/开头)、权限降级、环境重置(path=/usr/bin:/bin等)及安全捕获输出。

直接拼接、eval 执行或未经校验就传给 system/popen,是绝大多数 Shell 脚本被注入的根本原因。安全处理外部输入的核心不是“怎么转义”,而是“不让它进命令执行上下文”。
用参数化方式替代字符串拼接
Shell 本身不支持真正的参数化执行,但你可以通过 显式分隔参数 避免 shell 解析器介入:
- 错误写法:
eval "ls -l $user_input"—— 用户输入a; rm -rf /就会执行删除 - 正确写法:
ls -l -- "$user_input"——--明确终止选项解析,"$user_input"用双引号包裹防止空格截断,且不触发通配或变量展开 - 对多参数场景,优先用数组:
args=(); args+=(-l); args+=("$path"); ls "${args[@]}"
输入必须白名单过滤,不能只靠转义
转义(如用 printf %q)在复杂嵌套中不可靠,且无法防御逻辑绕过。应默认拒绝,只放行已知安全的字符:
Zynq‑7000 / Zynq UltraScale+ 硬件调试技能。适用于 Xilinx Zynq(Cortex‑A9/A53 + FPGA)Linux 环境,调试 I2C、I2S、UART、GPIO 等外设。包括设备树配置、内核驱动、用户空间调试工具、交叉编译和常见问题排查,支持 PetaLinux 开发。
- 只允许字母、数字、下划线、短横线:
case $input in [a-zA-Z0-9_-]*) ;; *) echo "invalid input" >&2; exit 1 ;; esac - 对路径类输入,额外限制不能含
..、不能以/开头(除非明确需要绝对路径)、禁止控制字符:[[ $input =~ ^[a-zA-Z0-9._-]+$ ]] && [[ $input != *..* ]] || exit 1 - 避免用
sed 's/[^a-z]//g'这类“清洗”逻辑——它可能留下危险组合,如rm$IFS-rf
敏感操作前做上下文隔离与权限降级
即使输入合规,也要防止它被用于越权操作:
- 脚本默认以最小权限用户运行;涉及文件操作时,先用
stat -c "%U:%G %a %n" "$target"检查属主和权限,拒绝操作不属于当前用户的敏感路径(如/etc、/root) - 对需 root 权限的操作,拆分为两阶段:第一阶段只做输入验证和预计算,输出可审计的命令清单;第二阶段由 sudo 单独执行,且 sudoers 中限制仅允许特定命令加固定参数(如
www-data ALL=(root) NOPASSWD: /usr/local/bin/fix-perm.sh /var/www/html/*) - 避免在脚本中直接读取
/proc、/sys或调用mount、iptables等高危命令,改用专用封装工具并严格限定作用域
环境变量和子命令输出也要当输入对待
攻击者常通过污染 PATH、IFS 或伪造 $(command) 输出来突破防线:
- 重置关键环境变量:
PATH=/usr/bin:/bin; unset IFS; LC_ALL=C,再执行后续逻辑 - 捕获外部命令输出时,禁用 glob 和 word splitting:
output=$(some_cmd); output=${output%%[$'\n\r\t ']}; output=${output##[$'\n\r\t ']},再校验内容格式 - 对
find、grep等命令,始终用-print0+read -r -d ''处理含空格或换行的路径,而非for f in $(find ...)










