SQLite,ASCII 字符 0x20 到 0x7E 检查约束

问题描述 投票:0回答:2

我有下表,我试图将“名称”列限制为范围从 0x20 到 0x7E 的 ASCII 字符(所有可打印的 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"); 

预期:应将名称为“Tom”的元组添加到表中(因为插入的名称仅包含可打印的 ASCII 字符)。结果:CHECK 约束失败:测试

sqlite check-constraints
2个回答
1
投票

反斜杠在 SQL 字符串中并不特殊。例如,'\x20' 是 4 个单独的字符,而不是转义的单个字符。所以你的

GLOB
模式总是匹配(因为 T 不是集合中的字符),并且
NOT
匹配,因此约束失败。


0
投票
解决方案
name NOT GLOB cast(x'2a5b5e202d7f5d2a' as TEXT)
说明

为了确保字符串中的所有字符都是可打印的 ASCII,我们尝试查找不是的字符。如果没有找到这样的字符,则该字符串是可打印的 ASCII。从概念上讲,查询可能如下所示:

name NOT GLOB '*[^\x20-\x7E]*'   -- (doesn't work in SQLite)

这里

GLOB
运算符匹配任何不在
0x20-0x7E
中的字符,并且由于我们用
NOT
否定表达式,如果没有找到范围之外的字符,查询将解析为逻辑
true
。但是,SQLite 不允许您转义字符串文字中的十六进制字符,例如,
'\x20'
不是十六进制编码的空格字符。作为解决方法,我们提供与字节序列
GLOB
相同的
x'2a5b5e202d7f5d2a'
模式,并将其转换为
TEXT
,留下:

name NOT GLOB cast(x'2a5b5e202d7f5d2a' as TEXT)

对于合法的开发人员来说,这可能太丑陋了,但对于我们这些顽皮的搞 SQL 注入的流氓来说,这简直是完美的。

PS:我在 SQL 盲注框架中实现了类似的逻辑。有兴趣的读者可以在这里找到它。

© www.soinside.com 2019 - 2024. All rights reserved.