向Python SQLite表插入数据时清理用户输入的正确方法是什么?
SQLite Python 开发防SQL注入最佳实践
1 为什么你找到的「安全示例」运行报错
你找到的安全示例是适配MySQL、PostgreSQL等数据库的写法,这类数据库的参数占位符用%s,但SQLite 不支持%s作为参数占位符,所以才会抛出sqlite3.OperationalError: near "%": syntax error语法错误。
SQLite支持两种参数占位符格式:
- 问号占位符:
?,按顺序传参 - 命名占位符:
:参数名,按字典传参
2 你当前的黑名单过滤方案存在的问题
黑名单过滤是极低效的SQL注入防护手段,存在两个核心缺陷:
- 极易被绕过:攻击者可以通过编码变形、大小写组合、特殊字符拼接等多种方式绕过你的黑名单规则,你永远无法穷举所有恶意字符
- 影响业务正常使用:如果业务允许用户名或地址包含
'、\这类合法字符,你的替换逻辑会直接破坏原始输入的正确性
3 防SQL注入的正确方案
防SQL注入的唯一核心最佳实践是使用参数化查询(预编译语句),不需要你自己实现任何SQL特殊字符过滤逻辑,数据库驱动会自动处理所有参数的转义,从根本上杜绝注入风险。
3.1 参数化查询的本质区别
- 错误写法(字符串拼接):将用户输入和SQL语句结构拼在一起,用户输入的恶意内容会被数据库当成SQL指令的一部分执行
- 正确写法(参数化查询):SQL语句结构和用户输入完全分离,数据库先编译SQL语句的结构,再将参数填入对应位置,参数的内容永远只会被当成普通值处理,不会被解析为SQL指令
3.2 SQLite 正确写法示例
查询示例
# 问号占位符写法 cursor.execute("SELECT admin FROM users WHERE username = ?", (username,)) # 命名占位符写法 cursor.execute("SELECT admin FROM users WHERE username = :username", {"username": username})
插入数据示例(适配你的业务场景)
import sqlite3 def insert_data(userID, username, location): # 业务规则校验(仅为了符合业务要求,不是防注入的必须步骤) user_id_str = str(userID) # 注意原代码的逻辑判断错误:要用or而不是and,否则会出现校验不生效的问题 if not user_id_str.isdecimal() or len(user_id_str) != 18: raise ValueError("userID必须为18位纯数字") if len(username) > 32: raise ValueError("用户名长度不能超过32位") if len(location) > 64: raise ValueError("地址长度不能超过64位") # 连接数据库执行参数化插入 conn = sqlite3.connect("your_database.db") cursor = conn.cursor() cursor.execute( "INSERT INTO users (userID, username, location) VALUES (?, ?, ?)", (user_id_str, username, location) ) conn.commit() conn.close()
3.3 补充建议
业务层面的格式校验可以保留,用于提前拦截不符合要求的输入,减少无效的数据库请求,但不要依赖业务校验做SQL注入防护,防注入的核心必须是参数化查询。
内容的提问来源于stack exchange,提问作者Ventus
相关产品推荐
相关产品推荐

