2个看起来相似的“更新”变体的工作方式不同

问题描述

| 这是快照1:
strr = \"UPDATE fileinfo SET file_name = ? WHERE md5sum = ?\"
cr.execute(strr,( rec[0],rec[1]) )
和#2:
strr = \"UPDATE fileinfo SET file_name = {0} WHERE md5sum = {1}\".format(rec[0],rec[1])
cr.execute(strr)
一个工作正常,而第二个失败。它抛出   sqlite3.OperationalError:无法识别   令牌:(rec [0]中的某些令牌,取决于输入数据,可能是\“ @ \”或\“!\”或传递给输入的任何字符串) python 3.2,win7 谢谢。     

解决方法

警告!错误的代码如下! 问题是在第二个示例中,您不是将字符串作为SQL字符串提供,而是作为文字值提供。那是不可能的!相反,您必须执行以下操作:
strr = \"UPDATE fileinfo SET file_name = \'{0}\' WHERE md5sum = \'{1}\'\".format(rec[0],rec[1])
cr.execute(strr)
注意其他单引号吗?这就是SQL字符串语法。 但是不要这样做! 问题是如果您替换的字符串中包含的字符被SQL解析器理解为字符串上下文内的文字字符以外的任何其他字符。最明显的例子是
\'
(单引号字符)本身。尽管您可以安全地使用md5sum参数,但文件名中确实出现了奇怪的事情(尤其是涉及非技术用户的地方!),因此一开始最好小心。 可以通过在替换过程中在值上添加额外的魔术引号来解决此问题,但是很容易出错(直到今天,大量的PHP程序还是有问题),并且这样做鉴于我们在使用准备好的语句方面有更好,更简单的解决方案,因此使用了错误的方式。 也很慢。使用准备好的语句(即您的第一个示例)会更快,因为SQL引擎可以解析代码一次,而不是每次解析一次,并且可以通过将要插入的值有效地放置在生成的字节码的正确位置来处理要注入的值。永远不需要重新计算查询计划(即SQLite在其内部创建的小程序),而且值本身也不会引起混乱。它们只是以正确的方式忠实地使用。     ,您显示的两个变体非常不同。首先,您使用数据库api填写参数-值已正确转义。 在第二种变体中,您仅使用pythons字符串格式将变量添加到SQL字符串-值不会转义,并且根据
rec[0]
rec[1]
的内容,您将使用格式错误的SQL。 还要注意,这是SQL注入漏洞的出路!