
本文讲解如何正确使用参数化查询从 mysql 表中检索同时匹配用户名和密码的单行记录,重点纠正 sql 语法错误、防止 sql 注入,并提供可直接运行的安全示例。
在实现登录功能时,一个常见误区是误用 LIKE 和逗号分隔的列名(如 username, password LIKE '%s','%s'),这在 SQL 中完全无效——MySQL 不支持这种语法,会导致语法错误或意外的全表扫描。正确的做法是:对每个字段单独比较,并用 AND 连接条件。
✅ 正确写法(推荐):
cursor.execute("SELECT * FROM user WHERE username = %s AND password = %s", (username, password))
ecreds = cursor.fetchall()
if len(ecreds) == 1:
print(f"Login successful. Welcome, {ecreds[0][1]}") # 假设 name 在第二列⚠️ 关键要点说明:
- 禁止字符串拼接 SQL:原代码中 "%"%(username,password) 属于危险的字符串格式化,极易引发 SQL 注入攻击(例如用户输入 ' OR '1'='1 可绕过验证)。
- 必须使用参数化查询:%s 占位符由数据库驱动(如 mysql-connector-python 或 PyMySQL)自动转义并安全绑定,这是唯一被认可的安全实践。
- = 而非 LIKE:登录校验需精确匹配,LIKE 引入通配符(%, _)不仅低效,还可能造成逻辑漏洞(如 'admin%' 匹配所有以 admin 开头的密码)。
- 密码不应明文存储:生产环境中,务必使用 bcrypt、argon2 等哈希算法对密码加盐哈希,并在查询后用 bcrypt.checkpw() 验证,而非直接比对数据库中的明文/哈希值。
? 进阶建议:
为提升健壮性,可进一步优化查询逻辑:
cursor.execute("SELECT id, username, role FROM user WHERE username = %s", (username,))
user = cursor.fetchone()
if user and bcrypt.checkpw(password.encode('utf-8'), user[3].encode('utf-8')): # 假设 pwd_hash 在第4列
print(f"Login successful. Welcome, {user[1]}")
else:
print("Invalid credentials.")总结:一次准确、安全的登录查询 = 正确的 SQL 条件(WHERE col1 = %s AND col2 = %s) + 参数化执行 + 密码安全哈希验证。摒弃字符串拼接与模糊匹配,是构建可信认证系统的第一步。
立即学习“Python免费学习笔记(深入)”;










