我在sqlite3数据库中有一个宽表,我希望动态查询Python脚本中的某些列。我知道it's bad to inject parameters by string concatenation,所以我尝试使用参数替换。
我发现,当我使用参数替换来提供列名时,我会得到意想不到的结果。一个最小的例子:
import sqlite3 as lite
db = lite.connect("mre.sqlite")
c = db.cursor()
# Insert some dummy rows
c.execute("CREATE TABLE trouble (value real)")
c.execute("INSERT INTO trouble (value) VALUES (2)")
c.execute("INSERT INTO trouble (value) VALUES (4)")
db.commit()
for row in c.execute("SELECT AVG(value) FROM trouble"):
print row # Returns 3
for row in c.execute("SELECT AVG(:name) FROM trouble", {"name" : "value"}):
print row # Returns 0
db.close()
有没有更好的方法来实现这一点,而不仅仅是将一个列名注入一个字符串并运行它?
答案 0 :(得分:1)
正如罗布刚在评论中指出的那样,有一篇相关的SO帖子包含了我的答案。这些替换结构被称为"占位符,"这就是我最初没有在SO上找到答案的原因。列名没有占位符模式,因为dynamically specifying columns is not a code safety issue:
归结为" safe"手段。传统观点是这样的 使用普通的python字符串操作将值放入您的 查询不安全"。这是因为有各种各样的事情 如果你这样做可能会出错,这些数据往往来自 用户并不在你的掌控之中。你需要100%可靠的方式 正确地转义这些值,以便用户无法在SQL中注入SQL 数据值并让数据库执行它。所以图书馆作家呢 这个工作;你永远不应该。
但是,如果您正在编写通用帮助程序代码来操作事物 在数据库中,这些考虑因素并不适用。你是 隐含地给任何可以调用此类代码的人访问所有内容 在数据库中;这是助手代码的重点。所以现在 安全问题是确保用户生成的数据永远不会 用在这样的代码中。这是编码中的一般安全问题,而且是 与盲目地执行用户输入字符串相同的问题。这是一个 将值插入查询的明显问题,因为那里 您希望能够安全地处理用户输入数据。
所以,解决方案是首先没有问题:使用字符串格式注入值,快乐,继续你的生活。
答案 1 :(得分:0)
为什么不使用字符串格式?
for row in c.execute("SELECT AVG({name}) FROM trouble".format(**{"name" : "value"})):
print row # => (3.0,)