python如何防止SQL注入攻击?
在您提供的 ORM 示例中,我们已经有了防止 SQL 注入的基本保障,因为我们使用了参数化查询。但是,为了进一步增强代码的清晰性和安全性,我们可以确保在分页查询和插入等操作中都使用参数化查询,同时加入类型验证以防止意外输入。
以下是修改后的 ORM 代码,加入了更全面的安全措施和分页功能:
import sqlite3
from abc import ABC, abstractmethod
class Database:
"""数据库连接管理类"""
def __init__(self, db_name):
self.connection = sqlite3.connect(db_name)
self.cursor = self.connection.cursor()
def commit(self):
self.connection.commit()
def close(self):
self.connection.close()
class BaseModel(ABC):
"""模型基类"""
@classmethod
@abstractmethod
def table_name(cls):
pass
@classmethod
def create_table(cls, db: Database):
"""创建表"""
raise NotImplementedError("Subclasses must implement this method.")
@classmethod
def all(cls, db: Database):
"""获取所有记录"""
db.cursor.execute(f"SELECT * FROM {cls.table_name()}")
return db.cursor.fetchall()
@classmethod
def insert(cls, db: Database, **kwargs):
"""插入记录"""
columns = ', '.join(kwargs.keys())
placeholders = ', '.join(['?'] * len(kwargs))
sql = f"INSERT INTO {cls.table_name()} ({columns}) VALUES ({placeholders})"
db.cursor.execute(sql, tuple(kwargs.values()))
db.commit()
@classmethod
def delete(cls, db: Database, record_id):
"""删除记录"""
db.cursor.execute(f"DELETE FROM {cls.table_name()} WHERE id = ?", (record_id,))
db.commit()
@classmethod
def paginate(cls, db: Database, page: int, per_page: int):
"""分页查询"""
if not isinstance(page, int) or not isinstance(per_page, int) or page < 1 or per_page < 1:
raise ValueError("页码和每页记录数必须是正整数")
offset = (page - 1) * per_page
db.cursor.execute(f"SELECT * FROM {cls.table_name()} LIMIT ? OFFSET ?", (per_page, offset))
return db.cursor.fetchall()
class User(BaseModel):
"""用户模型"""
@classmethod
def table_name(cls):
return "users"
@classmethod
def create_table(cls, db: Database):
db.cursor.execute("""
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
age INTEGER NOT NULL CHECK(age >= 0) -- 确保年龄是非负整数
)
""")
db.commit()
# 使用示例
if __name__ == "__main__":
db = Database("example.db")
# 创建表
User.create_table(db)
# 插入数据
User.insert(db, name="Alice", age=30)
User.insert(db, name="Bob", age=25)
User.insert(db, name="Charlie", age=35)
User.insert(db, name="David", age=40)
User.insert(db, name="Eve", age=28)
# 分页查询
page_number = 1 # 当前页码
records_per_page = 2 # 每页记录数
users_page_1 = User.paginate(db, page=page_number, per_page=records_per_page)
print(f"第 {page_number} 页用户列表:", users_page_1)
page_number = 2 # 查询下一页
users_page_2 = User.paginate(db, page=page_number, per_page=records_per_page)
print(f"第 {page_number} 页用户列表:", users_page_2)
# 清理
db.close()
代码增强解释
-
输入验证:
- 在
paginate
方法中增加了输入验证,确保page
和per_page
是正整数。
- 在
-
年龄约束:
- 在
create_table
方法中,给年龄列加了 CHECK 约束,确保只能插入非负整数。
- 在
-
SQL 注入预防:
- 所有 SQL 执行使用参数化查询,确保安全性,这也是防止 SQL 注入的骨干。
通过这些增强,代码变得更加健壮且安全,有效地防止了 SQL 注入、确保了输入的有效性,以及增加了错误处理的可能性。