如何在Python中安全地向SQLite PRAGMA语句传递参数?
解决SQLCipher密钥设置的SQL注入问题
核心问题
直接拼接用户输入的密码到PRAGMA key语句中确实存在SQL注入风险,虽然sqlcipher3的execute方法默认限制单语句执行,能挡住多语句注入,但仍有潜在隐患(比如密钥被意外截断、语法错误导致密钥失效),且常规的参数化绑定对PRAGMA语句不生效。
可行解决方案
方案1:连接时直接指定密钥(推荐)
sqlcipher3的connect方法支持直接传入key参数,无需手动执行PRAGMA语句,从根源避免字符串拼接问题:
from getpass import getpass import sqlcipher3 password = getpass('Password: ') # 连接阶段直接传递密钥,底层安全处理 con = sqlcipher3.connect(':memory:', key=password) cur = con.cursor() # 后续正常执行数据库操作
这个方法由库底层负责密钥的传递逻辑,完全规避SQL注入风险,是最安全高效的方式。
方案2:手动转义单引号后拼接
如果必须通过PRAGMA语句设置密钥,需要对密码中的单引号按SQL标准转义(用两个单引号表示一个单引号),再拼接语句:
from getpass import getpass import sqlcipher3 con = sqlcipher3.connect(':memory:') cur = con.cursor() password = getpass('Password: ') # 转义密码中的单引号,避免破坏SQL语法结构 escaped_password = password.replace("'", "''") cur.execute(f"PRAGMA key='{escaped_password}';")
转义后,即使用户输入hunter2'; DROP TABLE secrets;--,拼接后的语句会变成:
PRAGMA key='hunter2''; DROP TABLE secrets;--';
此时整个字符串会被当作密钥的一部分,不会被解析为额外的SQL语句,既不会执行恶意操作,也能正确设置密钥。
为什么参数化绑定失效
SQLite的参数化占位符仅支持数据操作语言(DML)语句(如INSERT、SELECT、UPDATE),而PRAGMA属于SQL的控制类指令,不支持参数绑定机制,因此使用?或命名占位符会触发语法错误。
内容的提问来源于stack exchange,提问作者Sam Zuk
相关产品推荐
相关产品推荐

