Php SQL查询一致地选择不匹配的行
我正在cookie和数据库中存储md5哈希。我有一个函数,Php SQL查询一致地选择不匹配的行,php,mysql,sql,Php,Mysql,Sql,我正在cookie和数据库中存储md5哈希。我有一个函数,validate\u cookie(),它读取此cookie并查询数据库以查找与此哈希关联的用户 validate\u cookie()调用另一个函数get\u user\u data()来执行实际的查询。get\u user\u data()被其他一些函数和脚本调用,因此它发送的查询非常一般。下面是函数: function get_user_data($info,$password=Null,$source=Null) { if(!
validate\u cookie()
,它读取此cookie并查询数据库以查找与此哈希关联的用户
validate\u cookie()
调用另一个函数get\u user\u data()
来执行实际的查询。get\u user\u data()
被其他一些函数和脚本调用,因此它发送的查询非常一般。下面是函数:
function get_user_data($info,$password=Null,$source=Null)
{
if(!$source)
{
$query = "SELECT * FROM `users` WHERE `id` = '".mysql_real_escape_string($info)."' OR `email` = '".mysql_real_escape_string($info)."' OR `cookie`='".mysql_real_escape_string($info)."'"; //Check to see if $info matches any column
}
else { $query = "SELECT * FROM `users` WHERE `".mysql_real_escape_string($source)."_token` ='".mysql_real_escape_string($info)."'";} //we got a social token
$result = mysql_query($query);
if($result)
{
$row = mysql_fetch_array($result);
if($password)
{
if(crypt($password, $row['password']) == $row['password']) //password matching
{
return $row;
} else {return "Password does not match!";}
}
else { return $row; }
}
else { return "Could not get result from database!";}
}
本例中的重要查询位于if(!source){}
块内。通过validate\u cookie()
调用get\u user\u data()
的方式,这个查询变成了(我已经测试过它确实变成了这个):
由于id
是一个int字段,并且email
中的所有内容都经过验证,因此应从该查询中选择的唯一行是那些具有匹配cookie
字段的行
但是,无论是从PHP脚本调用此查询,还是从PHPMyAdmin手动调用此查询,都将始终选择目标行和另一行:一个在其cookie
字段中只有NULL
的测试用例。稍微更改散列(这样它就不会匹配任何内容)仍然会选择相同的测试用例
我的查询是否有一种我不理解的错误形式?或
是否有一些神秘用法允许匹配NULL
字段?任何帮助都将不胜感激
另外,在我被告知我应该真正使用mysqli之前,是的,我知道这一点mysql
是老板的命令。当且仅当您确定sql语句演变为以下内容时:
select a,b,[c ...] from mytable where a='something' or b='something' [or ...]
对于a,b[…]不为空
您只应该得到一行,其中“a”或“b”不为null,并且是“某物”。
如果没有,您的数据库/系统/驱动程序或其他什么都有问题
有时“别人错了”我很想这么说,但这是我做的一个证明(在我的例子中,php_db2有时没有结果) 特别是,如果您确定您的语句在运行时是如何演变的,如果“本机”工具(这里是mysql admin)给出了相同的-错误的-结果,那么就存在问题,不在您的范围内 如果(看起来)您的数据库/驱动程序/安装中存在错误,您可以尝试使用类似的Workaround
select from ... where (a='som' and a is not null) or (b='som' and b is not null...) and so on
考虑使用“TODO:等待正确的db安装”之类的标记
顺便说一句:
它正在将哈希值转换为整数。你的测试ID是3。你的哈希以3开头。它使这些人平等
select cast('3b38f280e0203d7998a0d0898095ed56' as unsigned) as x
收益率为3
像这样修复它:
SELECT id, email, password, cookie,
case when `email` = '3b38f280e0203d7998a0d0898095ed56' then 'email'
when `id` = '3b38f280e0203d7998a0d0898095ed56' then 'id'
when `cookie` = '3b38f280e0203d7998a0d0898095ed56' then 'cookie'
else 'else' end as wtf
FROM `users`
WHERE
cast(`id` as char) = '3b38f280e0203d7998a0d0898095ed56' or
`email` = '3b38f280e0203d7998a0d0898095ed56' or
`cookie` = '3b38f280e0203d7998a0d0898095ed56'
如果您传入一个ID=3,那么这仍然有效,测试用例对所有3个字段都有
NULL
,或者只有cookie字段?假设任何输入结果都是相同的测试用例输出,那么必须满足一个条件<代码>或要求满足您列出的3个条件之一。使用限制1,年轻的一个。您确定$source
的值,并且它没有达到if
语句的else
条件吗?我不确定假定NULL===false
是否安全。这可能不是问题所在,但更安全的做法是执行is_null($source)
或将默认值设置为$source=false
,如果($source==false)也执行,那么限制1
将只返回测试用例,因为它是先排序的。而且,这似乎是一个太多的黑客,如果相同的条件得到满足,多行开始返回,并选择了错误的一个呢?哎哟,刚刚有人登录了其他人的帐户。在这里,我这次导出了表,并取出了所有敏感信息。现在我得到了我一直在谈论的结果:哇,我读过头了“…id是一个int字段…”,我知道的所有其他数据库系统都会给出一个sql错误,比如“不能将'3b..转换为整数”等等。我很幸运,我从来没有遇到过这样的问题。用我的mySql脚本。这一个出现在我的“记住奇怪的behvior列表”中,为此我花了一分钟才弄明白。。。如果你看看问题下面的评论,我根本不相信这是DB的问题,因为它太奇怪了。我甚至从来没有问过id
的具体值是什么。不过,sqlfiddle解决了这个问题。
SELECT id, email, password, cookie,
case when `email` = '3b38f280e0203d7998a0d0898095ed56' then 'email'
when `id` = '3b38f280e0203d7998a0d0898095ed56' then 'id'
when `cookie` = '3b38f280e0203d7998a0d0898095ed56' then 'cookie'
else 'else' end as wtf
FROM `users`
WHERE
cast(`id` as char) = '3b38f280e0203d7998a0d0898095ed56' or
`email` = '3b38f280e0203d7998a0d0898095ed56' or
`cookie` = '3b38f280e0203d7998a0d0898095ed56'