我最近在程序中发现了一个有趣的错误,它使用私钥为特定客户选择数据。请考虑以下事项:
SELECT `id` FROM (`customers`) WHERE `authenticationKey` = '#09209!ko2A-' LIMIT 1
密钥在请求时提供,并在进行查询之前进行适当的清理。但是,如果未提供密钥(应该在之前捕获;忽略该密钥),将产生类似于以下内容的查询:
SELECT `id` FROM (`customers`) WHERE `authenticationKey` = 0 LIMIT 1
哪个会从customers
- 表中返回一行 - 尽管它存储了正确的字符串密钥,例如在第一个示例中。
authenticationKey
- 字段的类型为VARCHAR(1024)
。
我的猜测是,这与松散的比较有关。造成这个问题的原因是什么,以及如何正确避免?
答案 0 :(得分:4)
MySQL将尝试将数据强制转换为类似的类型。在这种情况下,它会尝试将字符串转换为数字。任何默认为0的字符串都无法理解。
待办事项
select 0 = 'banana'
看到这一点。
使您的查询与'0'
而不是0
进行比较会解决问题。
<强> Example SQLFiddle 强>
答案 1 :(得分:1)
MySQL隐式将authenticationKey
的前导字符转换为int,直到找到不是有效数字的字符。我想所有以非数字字符开头的行都被视为0。
例如,这会产生'b',因为强制的int值是1:
select (case when '1abc' = 0 then 'a' else 'b' end);
但这会产生'a',因为前导char不是有效数字,所以强制int值为0:
select (case when '#1abc' = 0 then 'a' else 'b' end);
应用程序应该避免这种情况。毕竟,为什么在没有给出密钥时使用0
进行查询?