3

假设我有一个这样的 SQL 语句来检查用户登录:

SELECT * FROM users 
WHERE username='test@example.com', password='abc123', expire_date>=NOW();

SQL 中有没有办法专门确定哪些 WHERE 条件失败,而不必将每个条件分成自己的查询并单独测试?

在这个特定的示例中,它允许开发人员准确地告诉用户他们尝试登录失败的原因。

出于我的目的,我使用的是 PHP/MySQL。

4

5 回答 5

6

好吧,您可以做的一件事是更改您的查询,使其仅与用户名匹配。然后在代码中检查密码和到期日期,返回相应的错误。

另外,我希望您的示例查询是一种简化;当然,您应该对密码进行加盐/加密/散列处理,并且您应该包括一些限制在特定时间范围内失败尝试次数的内容,等等......

至于您的实际问题(与您正在寻找的结果相反),没有办法从 where 子句中获取该信息。你可以做的最接近的是:

SELECT *,
    CASE WHEN Password = 'asdf' THEN 1 ELSE 0 END AS IsPasswordMatch,
    CASE WHEN Expiration >= NOW() THEN 1 ELSE 0 END AS IsActiveAccount
FROM Users
WHERE Username = 'user'
于 2009-09-11T17:17:46.297 回答
4

在 MySQL 中,您可以将布尔表达式放在选择列表中。布尔表达式在 true 时计算为整数 1,在 false 时计算为整数 0。

SELECT password = 'abc123' AS is_authenticated,
       expire_date >= NOW() AS is_not_expired
FROM users
WHERE username='test@example.com';

注意: 如果您需要编写适用于其他品牌 RDBMS 的查询,请记住,布尔表达式的这种使用是非标准的。使用CASE其他人发布的语法。

PS:这与您的问题相切,但我敦促您不要以明文形式存储密码。存储加盐密码的哈希摘要。请参阅密码盐如何帮助抵御彩虹表攻击?

于 2009-09-11T17:25:00.910 回答
1

不,where 子句作为一个块应用,并且使用了各种技术,因此不必扫描所有行。另外,你怎么知道哪一行是你想要的?

此外,您可能不想过多地告诉用户登录尝试失败的原因。说得太多会导致诸如帐户挖掘和密码攻击等漏洞利用。

编辑如果您确实想向用户显示此内容,请将您的逻辑拆分为不同的部分:

  1. 验证身份
    操作:从数据库中获取相应的用户行
    结果:
    • 如果不存在这样的行 => 无效帐户
    • 如果返回行,则继续执行步骤 2。
  2. 验证凭据
    操作:根据提供的密码检查存储的凭据(密码、密码哈希或加密密码),密码的处理方式与凭据存储方式相同。
    结果:
    • 不匹配 => 密码/凭据无效
    • 匹配 => 成功登录尝试
  3. 登录用户
    操作:将数据添加到会话等。
于 2009-09-11T17:20:02.970 回答
0

您可能只需要用“AND”分​​隔 where 子句的各个部分

SELECT * FROM users 
WHERE username='test@example.com'
   And password='abc123'
   And expire_date>=NOW();
于 2009-09-11T17:24:44.623 回答
0

这是我想出的:

SELECT
  IF(mem_username='test@example.com','true','Error: Bad Username') AS mem_username,
  IF(mem_password ='abc123','true','Error: Bad Password') AS mem_password'
FROM MEMBERS
WHERE mem_username='test@example.com' AND mem_password='abc123'

这样我可以在代码中检测错误消息,然后根据需要显示它们。

注意:对于所有引用示例代码的安全问题的人,感谢您的关注。但是,这不是真正的生产代码,这只是一个简单的示例来演示我的问题。很明显,您不应该以明文形式存储密码,也不应该向用户详细说明登录失败的原因。

于 2009-09-11T17:30:48.997 回答