我有下面的表,我试图限制列“名称”的ASCII字符范围从0x20到0x7E(所有可打印的ASCII字符)。为什么我的检查约束不起作用?
CREATE TABLE test
(
id INTEGER NOT NULL,
name TEXT NOT NULL CHECK(name NOT GLOB '*[^\x20-\x7E]*'),
PRIMARY KEY(id)
)
例如:
INSERT INTO test (name) VALUES("Tom");
预期:应添加一个touple,名称为:“Tom”添加到表中(因为插入的名称仅由可打印的ASCII字符组成)。结果:重复约束失败:测试
2条答案
按热度按时间aurhwmvo1#
反斜杠在SQL字符串中并不特殊。例如,“\x20”是4个单独的字符,而不是转义的单个字符。所以
GLOB
模式总是匹配(因为T不是集合中的字符),NOT
使它失败,因此约束失败。bis0qfac2#
解决方案
说明
为了确保字符串中的所有字符都是可打印的ASCII,我们尝试查找不是的字符。如果没有找到这样的字符,则字符串是可打印的ASCII。从概念上讲,查询可能看起来像这样:
这里
GLOB
运算符匹配任何不在0x20-0x7E
中的字符,并且由于我们用NOT
否定表达式,如果没有找到范围外的字符,查询将解析为逻辑true
。但是,SQLite不允许对字符串字面量中的十六进制字符进行转义,例如,'\x20'
不是十六进制编码的空格字符。作为一种变通方法,我们提供与字节序列x'2a5b5e202d7f5d2a'
相同的GLOB
模式,并将其转换为TEXT
,剩下的是:现在,这可能是太丑陋的合法开发人员,但对我们顽皮的流氓搞SQL注入这只是完美的。
PS:我在我的Blind SQL Injection框架中实现了类似的逻辑。感兴趣的读者可以在这里找到它。