Python3 SQLite中能否安全使用.format()语法编写executescript语句?
绝对不要用
str.format()处理SQL参数! 你的想法里用str.format()直接替换SQL模板中的变量是极度危险的,完全绕开了SQLite提供的参数化查询安全机制,会直接暴露在SQL注入攻击之下——就像你举的例子里,当c的值是"Robert'); DROP TABLE foo; --"时,用format()替换后,最终执行的SQL会变成:
... INSERT INTO foo VALUES ('a', 'b', 'Robert'); DROP TABLE foo; --'); ...
这会直接删除你的foo表,更别说更复杂的恶意注入操作了。
正确的解决方案:用SQLite原生的命名参数
其实SQLite本身就支持命名占位符,完全能满足你用清晰命名替代问号的需求,同时还能自动帮你处理变量转义,彻底避免SQL注入。
有两种常用的命名参数风格:
- 使用
:name作为占位符 - 或者用
@name(ODBC风格)
具体用法很简单:
- 你的SQL模板(从文件读取的内容)里写成这样:
... INSERT INTO foo VALUES (:a, :b, :c); ... - 执行的时候,把参数以字典的形式传给
execute()(或者executemany()):params = {'a': 'a', 'b': 'b', 'c': "Robert'); DROP TABLE foo; --"} c.execute(fp.read(), params)
这样SQLite会自动识别:a、:b、:c这些占位符,安全地把参数值转义后插入到SQL语句中,完全不用担心注入问题,而且命名参数比问号清晰太多,长SQL里也能一眼对应上每个变量的位置。
关于executescript()的注意点
如果你本来想用executescript()执行多语句脚本,要注意这个方法不支持参数化。这种情况下,你最好把脚本拆分成独立的SQL语句,对每个需要参数的语句单独用execute()加命名参数来执行;如果是批量操作,就用executemany()配合命名参数。
总结
你想要的“命名占位符+长SQL模板”的需求完全可以实现,但绝对不能用字符串格式化来做——必须依赖SQLite原生的参数化查询机制,既保证了代码的可读性,又守住了安全性的底线。
内容的提问来源于stack exchange,提问作者Sebastian Bartos
相关产品推荐
相关产品推荐

