python sql转义,关于sql:在WHERE-Clause中转义的Python / SQLite3

我应该如何在Python中为SQLite3进行真正的转义?

如果我用谷歌搜索(或搜索stackoverflow),会有很多问题,每次响应都是这样的:

dbcursor.execute("SELECT * FROM `foo` WHERE `bar` like ?", ["foobar"])

这有助于防止SQL注入,并且如果我只用" ="进行编译,就足够了,但它当然不会剥离通配符。

所以如果我这样做

cursor.execute(u"UPDATE `cookies` set `count`=? WHERE `nickname` ilike ?", (cookies, name))

一些用户可以提供"%"作为昵称,并用一行替换所有cookie条目。

我可以自己过滤它(嗯……我可能还是会忘记那些鲜为人知的通配符之一),我可以在昵称和昵称上使用小写字母,并用" ="替换" ilike",但是我真正想做的是 类似于以下内容:

foo = sqlescape(nick)+"%"

cursor.execute(u"UPDATE `cookies` set `count`=? WHERE `nickname` ilike ?", (cookies, foo))

为什么要使用LIKE进行除模糊搜索之外的任何操作?

您可以忽略搜索本身吗? 那不是我问的。 (或者更确切地说:我可以将其用于模糊搜索,不会稍微改变问题,对吗?)

?参数旨在避免SQL字符串(以及其他有问题的数据类型,如浮点数和blob)的格式问题。

LIKE / GLOB通配符在不同级别上起作用;它们始终是字符串本身的一部分。

SQL允许对它们进行转义,但是没有默认的转义字符。您必须使用ESCAPE子句进行选择:

escaped_foo = my_like_escape(foo,"\")

c.execute("UPDATE cookies SET count = ? WHERE nickname LIKE ? ESCAPE '\',

(cookies, escaped_foo))

(并且您必须为%和_(LIKE)或*和?(GLOB)编写自己的my_like_escape函数。)

好吧……这就是这样做的方法,虽然有很多帮助,但是却使每个用户都无法编写自己的转义功能。

所以我认为没有更好/好的解决方案:-/容易出错,并且每个人都可以自己工作。 几乎是我最坏的情况。

您已经避免使用参数化查询来进行彻底的代码注入。现在看来,您正在尝试与用户提供的数据进行模式匹配,但是您希望将用户提供的数据部分视为文字数据(因此不能使用通配符)。您有几种选择:

只需过滤输入。 SQLite的LIKE仅将%和_理解为通配符,因此很难弄错它。只要确保始终过滤输入即可。 (我的首选方法:在构造查询之前进行过滤,而不是在读取用户输入时进行过滤)。

通常,"白名单"方法被认为比删除特定的危险字符更安全,更容易。也就是说,不要从字符串(和您所说的任何"鲜为人知的通配符")中删除%和_,而是扫描字符串并仅保留所需的字符。例如,如果您的"昵称"可以包含ASCII字母,数字,"-"和"。",则可以按以下方式进行清理:

name = re.sub(r"[^A-Za-z\d.-]","", name)

该解决方案特定于您要匹配的粒子字段,并且对于关键字段和其他标识符非常有效。如果必须使用RLIKE进行搜索,我肯定会这样做,因为RLIKE接受完整的正则表达式,因此要注意的字符很多。

如果您不希望用户提供通配符,为什么无论如何仍要在查询中使用LIKE?如果查询的输入来自代码中的很多地方(或者甚至您正在编写一个库),那么如果可以完全避免使用LIKE,则可以使查询更安全:

这是不区分大小写的匹配:

SELECT * FROM ... WHERE name = 'someone' COLLATE NOCASE

在您的示例中,您使用前缀匹配(" sqlescape(nick)+"%"")。进行精确搜索的方法如下:

size = len(nick)

cursor.execute(u"UPDATE `cookies` set `count`=? WHERE substr(`nickname`, 1, ?) = ?",

(cookies, size, nick))

嗯,通常您只想用不以任何特殊方式解释"%"的普通" ="比较替换" ilike"。转义(有效地将不良模式列入黑名单)容易出错,例如即使您设法逃避了所使用的sqlLite版本中的所有已知模式,任何将来的升级都可能使您处于危险之中,等等。

我不清楚,为什么要基于用户名的模糊匹配来批量更新Cookie。

如果您真的想这样做,我的首选方法是先选择列表,然后决定在应用程序级别进行更新以保持最大程度的控制。

是的..因为那是我的问题的解决方案。 等等...不是!

使用字符串format -ing可以通过几种非常有趣的方法来实现。

从Python的文档中:

The built-in str and unicode classes provide the ability to do complex variable substitutions and value formatting via the str.format() method:

s ="string"

c ="Cool"

print"This is a {0}. {1}, huh?".format(s,c)

#=> This is a string. Cool, huh?

您可以使用字符串格式进行其他一些巧妙的技巧:

"First, thou shalt count to {0}".format(3) # References first positional argument

"Bring me a {}".format("shrubbery!")       # Implicitly references the first positional argument

"From {} to {}".format('Africa','Mercia')      # Same as"From {0} to {1}"

"My quest is {name}"                       # References keyword argument 'name'

"Weight in tons {0.weight}"                # 'weight' attribute of first positional arg

"Units destroyed: {players[0]}"            # First element of keyword argument 'players'.`

我知道如何格式化字符串...但是这对查找所有必须转义的内容(不仅是我能记住的那两件事)没有帮助-根本不是我要的...。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值