本文目录导读:

- 案例1:使用
sqlite3(内置数据库) - 案例2:使用
MySQL(通过mysql-connector-python或PyMySQL) - 案例3:使用
PostgreSQL(通过psycopg2) - 案例4:使用 ORM 框架(如 SQLAlchemy、Django ORM)
- 特别注意事项
- 记住这三条铁律
防止SQL注入是Web开发中最基本的安全要求,在Python中,最核心的原则是:永远不要直接拼接SQL语句,始终使用参数化查询。
下面通过几个常见的Python数据库操作案例,演示如何安全地防止SQL注入。
案例1:使用 sqlite3(内置数据库)
这是最容易出错的场景,演示错误做法和正确做法。
❌ 错误做法(极易被注入)
import sqlite3
conn = sqlite3.connect('test.db')
cursor = conn.cursor()
# 假设用户输入: user_input = "' OR '1'='1"
user_input = input("请输入用户名:")
# 直接拼接 SQL —— 这是高危操作!
sql = f"SELECT * FROM users WHERE username = '{user_input}'"
cursor.execute(sql)
- 如果用户输入
' OR '1'='1,SQL 变成SELECT * FROM users WHERE username = '' OR '1'='1',会返回所有用户数据。
✅ 正确做法(使用参数化查询)
import sqlite3
conn = sqlite3.connect('test.db')
cursor = conn.cursor()
user_input = input("请输入用户名:")
# 使用 ? 占位符,将用户输入作为参数传递
sql = "SELECT * FROM users WHERE username = ?"
cursor.execute(sql, (user_input,)) # 注意:参数必须是元组或列表
- SQL语句和用户数据完全分离,数据库引擎会自动处理转义,
' OR '1'='1只会被当作一个普通字符串去匹配,不会破坏SQL结构。
案例2:使用 MySQL(通过 mysql-connector-python 或 PyMySQL)
原理与sqlite3相同,只是占位符不同(MySQL通常使用 %s)。
✅ 正确做法
import mysql.connector
conn = mysql.connector.connect(
host="localhost",
user="root",
password="yourpassword",
database="testdb"
)
cursor = conn.cursor()
user_input = input("请输入用户名:")
# MySQL 推荐使用 %s 作为占位符
sql = "SELECT * FROM users WHERE username = %s"
cursor.execute(sql, (user_input,))
results = cursor.fetchall()
案例3:使用 PostgreSQL(通过 psycopg2)
PostgreSQL使用 %s 占位符(与MySQL相同,但底层实现不同)。
✅ 正确做法
import psycopg2
conn = psycopg2.connect(
host="localhost",
dbname="testdb",
user="postgres",
password="yourpassword"
)
cursor = conn.cursor()
user_input = input("请输入用户名:")
sql = "SELECT * FROM users WHERE username = %s"
cursor.execute(sql, (user_input,))
案例4:使用 ORM 框架(如 SQLAlchemy、Django ORM)
ORM框架本身已经防止了SQL注入,但前提是你不要执行原生SQL。
✅ SQLAlchemy 正确用法
from sqlalchemy import create_engine, text
engine = create_engine('sqlite:///test.db')
with engine.connect() as conn:
user_input = input("请输入用户名:")
# 使用 bind parameters(绑定参数)
result = conn.execute(
text("SELECT * FROM users WHERE username = :username"),
{"username": user_input}
)
✅ Django ORM 正确用法
from django.contrib.auth.models import User
user_input = request.GET.get('username')
# Django ORM 会自动参数化,无需担心注入
users = User.objects.filter(username=user_input)
特别注意事项
LIKE 查询也需要参数化
即使使用LIKE,也要用参数,不要在SQL里拼接百分号。
# ✅ 正确
sql = "SELECT * FROM users WHERE username LIKE ?"
cursor.execute(sql, (f"%{user_input}%",))
IN 子句的参数化
对于IN查询,不同数据库有不同做法,但不要拼接。
# sqlite3 的一种替代写法(安全)
ids = [1, 2, 3]
placeholders = ','.join('?' * len(ids))
sql = f"SELECT * FROM users WHERE id IN ({placeholders})"
cursor.execute(sql, ids)
存储过程也可能有风险
如果存储过程内部拼接了SQL,同样存在注入风险。
记住这三条铁律
- 绝不拼接:永远不要用
f"SELECT ... {user_input}"或"SELECT " + user_input这种方式。 - 使用占位符:(sqlite3)、
%s(MySQL/PostgreSQL)、name(SQLAlchemy等)。 - 参数作为独立参数传入:
execute(sql, (user_input,)),而不是写进SQL字符串里。
如果你的代码已经用上了ORM(Django ORM、SQLAlchemy ORM),并且只使用ORM的方法(不写原生SQL),那么默认就是安全的,但一旦写了 raw() 或 text(),就需要手动参数化。
安全无小事,一个简单的就能堵住90%的注入漏洞。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播