5.7.3 依赖命令与路径安全

依赖命令与路径安全的核心是可控、可预期与最小化信任:脚本必须显式声明依赖、验证命令来源,避免被环境变量或同名恶意程序劫持。

文章图片

关键原则与命令解释#

  • 固定 PATH:只保留可信目录,避免包含当前目录 .
  • export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
  • 校验命令存在:
  • command -v rsync:返回命令路径,非零表示缺失
  • type -a rsync:列出所有匹配路径
  • 校验真实路径与权限:
  • readlink -f /usr/bin/rsync:解析真实路径
  • stat -c '%U %A %n' /usr/bin/rsync:查看属主与权限
  • 清理环境变量:
  • env -i PATH=... /bin/bash script.sh:空环境运行
  • 重点变量:LD_PRELOADIFSBASH_ENV
  • 命令缓存:
  • hash -r:刷新 Shell 命令路径缓存

可执行示例:依赖检查与路径锁定#

文件路径/opt/scripts/backup.sh

#!/usr/bin/env bash
set -euo pipefail

# 1) 固定 PATH,避免从不可信目录加载
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

# 2) 清理危险环境变量
unset LD_PRELOAD IFS BASH_ENV

# 3) 依赖清单
DEPS=(/usr/bin/rsync /usr/bin/ssh /bin/date)

# 4) 检查命令是否存在与权限
for cmd in "${DEPS[@]}"; do
  if [[ ! -x "$cmd" ]]; then
    echo "ERROR: missing or not executable: $cmd" >&2
    exit 1
  fi
  echo "OK: $(stat -c '%U %A %n' "$cmd")"
done

# 5) 记录版本,确保一致性
/usr/bin/rsync --version | head -n1
/usr/bin/ssh -V 2>&1 | head -n1

# 6) 业务逻辑(示例:备份)
SRC="/data/"
DST="backup@10.0.0.10:/data/backup/"
/usr/bin/rsync -avz --delete "$SRC" "$DST"
echo "Backup finished at $(/bin/date '+%F %T')"

预期效果
- 缺少依赖直接报错退出
- 命令来源与权限输出清晰
- 备份命令使用绝对路径,避免路径劫持

安装与依赖来源(示例)#

使用系统包管理器安装并校验来源

# Debian/Ubuntu
sudo apt update
sudo apt install -y rsync openssh-client
apt-cache policy rsync | head -n3

# RHEL/CentOS/Rocky
sudo yum install -y rsync openssh-clients
rpm -qi rsync | head -n5

验证签名与来源(示例)

rpm -q --qf '%{SIGPGP:pgpsig}\n' rsync

排错指南(常见问题与定位命令)#

  1. 命令被同名程序劫持
    - 现象:脚本执行异常、输出不同
    - 排查:
    bash type -a rsync command -v rsync readlink -f "$(command -v rsync)"
    - 解决:固定 PATH、使用绝对路径、删除可疑文件

  2. 更新命令后仍执行旧路径
    - 排查:
    bash hash
    - 解决:
    bash hash -r

  3. 环境变量被污染导致行为异常
    - 排查:
    bash env | egrep 'LD_PRELOAD|IFS|BASH_ENV'
    - 解决:env -i 启动或 unset

练习#

  1. 写一个脚本 check_deps.sh,检查 curltargzip 是否存在,并输出路径与权限。
  2. ~/bin 放置一个假 rsync,观察 type -a rsync 的输出变化,然后通过固定 PATH 解决。
  3. 使用 env -i 运行脚本,验证 LD_PRELOAD 对脚本行为的影响是否被消除。