首页/安全/漏洞与攻击面速查/命令注入原理与防护
Web 漏洞原理与防护55 条

命令注入原理与防护

系统命令注入源于把用户输入拼接进 shell 命令:&、|、;、$() 等元字符让输入变成新命令;防护是避免 shell 拼接(用参数数组调用),对必须校验的参数严格限制取值域。

漏洞与攻击面速查安全更新于 2026-10-13

命令注入是什么

命令注入的成因是把用户输入拼接进 shell 命令字符串:分号、管道、与号、反引号、命令替换等元字符让输入变成新的命令,服务器最终执行的不再是开发者预期的程序。它的危害是主机级的——一旦成功,攻击者获得的是运行服务的账号权限,可读取文件、发起内网请求、写入持久化配置。防护的第一选择是彻底绕开 shell,用参数数组方式调用程序;无法绕开时,除了严格的输入域限制,还要自行完成正确的引用与转义。

基本信息

风险类别OWASP Top 10 2021 A03 注入类;CWE-78
常见入口网络诊断(ping、traceroute)、文件格式转换、备份脚本、系统信息查询
危险元字符分号、管道、与号、反引号、命令替换、换行
危害以服务账号权限执行任意命令,读取数据与横向探测
首选防护参数数组调用,不经过 shell
兜底手段输入域白名单、最小权限运行、出站限制

典型场景

  • 运维平台提供网络诊断按钮,把用户填写的地址拼进 ping 或 traceroute
  • 媒体处理功能调用转换工具,把文件名拼进命令行
  • 定时备份脚本读取数据库里的参数并拼进系统命令
  • 日志分析功能调用外部文本工具处理用户上传的文件
  • 系统信息查询页面调用平台命令并拼接参数
  • 容器内应用调用宿主命令,权限与影响面更大

风险与安全对比

风险与安全对比
风险:os.system('ping -c 1 ' + ip)
安全:subprocess.run(['ping', '-c', '1', ip], check=True)
参数数组方式不经过 shell,元字符失去特殊含义
# 其他语言同理:Java 用 ProcessBuilder 的列表构造,PHP 用数组形式的 proc_open
# 避免使用拼接字符串后再交给 shell 的调用方式

输入校验补充(Python)

输入校验补充(Python)
import ipaddress
try:
    ip = str(ipaddress.ip_address(user_input))
except ValueError:
    raise ValueError('invalid ip')
# 允许的输入域越窄(IP、域名、枚举值),风险面越小
# 域名场景要同时限定字符集与长度,并禁止以短横线开头结尾

调用方式风险对照

调用方式是否经过 shell风险
字符串拼接后交给 shell是最高,元字符全部生效
参数数组调用否低,元字符按普通字符处理
必须使用 shell 的固定命令是中,参数需严格白名单与引用
调用内部函数库替代外部命令否最低,推荐优先采用
必须使用 shell=True 时,需要自行完成整体引用转义,出错概率高,应尽量避免。
运行权限也是防线:以专用低权限账号运行外部命令、限制其可写目录与出站网络,即使注入成功也能压缩影响范围。

易错点

  • 只过滤分号与管道符:换行、反引号、$() 等仍是危险元字符,应改用参数数组而非过滤
  • 认为参数数组只是写法差异:它从结构上消除了元字符解释,这是防护方式的根本变化
  • 把过滤放在字符串拼接之后:此时输入已与命令混在一起,过滤无法可靠区分
  • 忽略间接调用链:脚本文件、配置文件与环境变量里的命令同样可能被拼接
  • 以高权限运行服务:注入成功即获得主机级控制,应按最小权限运行
  • 只修被通报的功能:同类诊断与转换功能常共用同一套调用逻辑,需统一改造

数据来源与参考

  • OWASP OS Command Injection Defense Cheat Sheet
  • Python subprocess 文档
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌