直接拼接sql字符串必然导致sql注入,因用户输入与sql结构混同;必须使用参数化查询(如cursor.execute("insert...%s", (username, pwd_hash))),表名等无法参数化的部分须用白名单校验。

直接用 pymysql 或 mysql-connector-python 连 MySQL 做注册登录校验是可行的,但必须手动处理密码哈希、SQL 注入防护、连接复用和事务边界——否则上线当天就可能丢用户数据或被拖库。
为什么不能直接拼接 SQL 字符串做 INSERT/SELECT
用户注册时若写成 "INSERT INTO users (username, password) VALUES ('" + username + "', '" + password + "')" ,遇到用户名为 ' OR '1'='1 就会触发注入;登录校验同理。MySQL 驱动本身不替你过滤,得靠参数化查询。
- 所有用户输入必须进
cursor.execute(sql, (param1, param2))的第二个参数元组 -
username和password_hash字段在建表时建议设为NOT NULL且username加唯一索引 - 别用
md5()或明文存密码,Python 侧统一用bcrypt.hashpw()或passlib.hash.pbkdf2_sha256
注册流程中容易漏掉的三件事
很多实现只管插数据,忽略业务一致性约束:
- 先
SELECT COUNT(*) FROM users WHERE username = %s判重,再INSERT,中间没加数据库层唯一约束的话,并发注册可能写入重复用户名 - 注册成功后没用
connection.commit(),连接关闭时事务回滚,用户以为注册成功实则没存进去 - 没对
password做长度和字符类型校验(比如允许空密码),前端限制可绕过,后端必须兜底
登录校验必须验证密码哈希而非明文比对
查出用户记录后,不能用 if row['password'] == input_password: —— 这说明密码是明文存的,属于严重安全漏洞。
- 从 DB 查到的是哈希值(如
$2b$12$...),用bcrypt.checkpw(input_password.encode(), hashed_password.encode())校验 - 查库语句必须是
SELECT id, username, password_hash FROM users WHERE username = %s,别 SELECT *,也别漏掉password_hash字段 - 查不到用户或密码错,都统一返回“用户名或密码错误”,避免泄露用户名是否存在
连接管理别每次请求都新建再 close
频繁 pymysql.connect() + .close() 会打满 MySQL 的 max_connections,尤其并发稍高时连接池是刚需。
- 用
pymysqlpool或更通用的SQLAlchemy的create_engine(..., pool_size=5, max_overflow=10) - Web 框架里(如 Flask)推荐把连接池挂到
app.config或全局变量,而不是每次视图函数里临时连 - 如果坚持手写连接,至少确保
try...finally中调用connection.close(),否则连接泄漏
真正难的不是连上 MySQL,而是让每一次 INSERT 和 SELECT 都在正确事务里、带正确参数、用正确哈希方式、走正确连接路径——这些点漏掉任意一个,系统就处在可被利用的脆弱状态。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











