必须杜绝直接拼接变量进MySQL命令行,应使用python等语言配合参数化查询,或严格白名单校验;数据库账号须遵循最小权限原则。

直接拼接变量进 mysql 命令行几乎必然导致 SQL 注入,尤其在自动化脚本中常混用用户输入(如主机名、标签、ID)和 SQL 逻辑,必须杜绝 mysql -e "SELECT * FROM t WHERE name = '$name'" 这类写法。
用 mysql --defaults-file 隔离凭证与语句
避免在命令行暴露密码,也防止参数被 shell 层或 SQL 层二次解析。关键不是“怎么传参数”,而是“不让参数进命令字符串”。
-
mysql命令本身不支持安全的参数化查询,--defaults-file是唯一能绕过命令行拼接的官方机制 - 动态生成临时配置文件(权限
600),只包含[client]段和user/password/host,不写database - SQL 逻辑改用
mysql --defaults-file=/tmp/cred.cnf -D mydb+ 标准输入传入,例如:echo "SELECT * FROM hosts WHERE hostname = ?" | mysql --defaults-file=/tmp/cred.cnf -D infra
—— 注意:这里?不会被识别,仅作占位示意;实际仍需外部处理
真正安全的做法:用 Python/Perl 等语言做中间层
Bash 本身没有参数化 SQL 能力,硬要在 shell 里“过滤单引号”或“转义反斜杠”是徒劳的——攻击者可用十六进制编码、宽字节截断、注释符绕过所有简单过滤。
- 把高风险操作(如根据用户输入查表、删记录、建库)全部交给
python3 -c或独立脚本,使用sqlite3(内置)或pymysql/mysql-connector-python - 示例(安全):
python3 -c " import sys, pymysql conn = pymysql.connect(read_default_file='/etc/mysql/deploy.cnf', database='infra') with conn.cursor() as cur: cur.execute('SELECT ip FROM servers WHERE env = %s AND role = %s', (sys.argv[1], sys.argv[2])) print(cur.fetchone()[0] if cur.rowcount else '') " prod web - 禁止在
python -c中拼接sys.argv到 SQL 字符串里;必须用%s占位符,由驱动完成绑定
如果非得用纯 Bash,只能限制输入为严格白名单
适用于 ID、状态码、枚举值等已知有限集合的场景,不是“防注入”,而是“砍掉注入可能性”。
- 用
case显式列出所有合法值:case "$env" in prod|staging|dev) : ;; *) echo "Invalid env: $env" >&2; exit 1 ;; esac
- 数字 ID 必须用
[[ "$id" =~ ^[0-9]+$ ]] || exit 1,不能只检查是否非空 - 绝对不要对 hostname、username、路径类字段做白名单——它们天然不可穷举,此时 Bash 就不该碰 SQL
最易被忽略的一点:即使用了参数化查询,若数据库账号权限过大(比如赋予了 DROP TABLE 或 LOAD_FILE),一次注入失败也可能因权限失控导致横向渗透。自动化脚本连接数据库的账号,必须按最小权限原则单独创建,且禁用 FILE、PROCESS、SUPER 等高危权限。

















