Определите, какая часть (части) оператора WHERE не выполнена - PullRequest
3 голосов
/ 11 сентября 2009

Допустим, у меня есть такой SQL-оператор, который проверяет логин пользователя:

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

Есть ли в SQL способ конкретно определить, какие условия WHERE не выполняются, без необходимости разделять каждое условие на собственный запрос и тестировать отдельно?

В этом конкретном примере это позволит разработчику точно указать пользователям причину, по которой их попытка входа не удалась.

В своих целях я использую PHP / MySQL.

Ответы [ 5 ]

6 голосов
/ 11 сентября 2009

Ну, одну вещь, которую вы могли бы сделать, это изменить свой запрос так, чтобы он совпадал только с именем пользователя. Затем в коде вы проверяете пароль и срок действия, возвращая соответствующие ошибки.

Кроме того, я надеюсь, что ваш пример запроса является упрощением; Конечно, вы должны защищать / шифровать / хэшировать свои пароли, и вы должны включить что-то, что ограничивает количество неудачных попыток в течение определенного периода времени и т. Д.

Что касается вашего фактического вопроса (в отличие от результатов, которые вы ищете), нет способа получить эту информацию из предложения 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'
4 голосов
/ 11 сентября 2009

В MySQL вы можете помещать логические выражения в список выбора. Булевы выражения оцениваются в целое число 1, если оно истинно, или в целое число 0, когда ложно.

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

примечание: Если вам нужно написать запрос, который работает с другими брендами СУБД, имейте в виду, что использование логических выражений не является стандартным. Используйте синтаксис CASE, опубликованный другими людьми.

PS: Это касается вашего вопроса, но я призываю вас не хранить пароли в открытом виде. Сохраните хэш-дайджест соленого пароля. См. Как соль пароля помогает против атаки радужной таблицы?

1 голос
/ 11 сентября 2009

Нет, предложение where применяется как блок, и используются различные методы, так что не все строки должны быть отсканированы. Кроме того, как вы узнали бы, какой ряд был тем, который был желателен?

Кроме того, вы, вероятно, не хотите слишком много рассказывать пользователю о том, почему попытка входа не удалась. Слишком много слов позволяет использовать такие уязвимости, как интеллектуальный анализ учетных записей и парольные атаки.

edit Если вы действительно хотите отобразить это для своего пользователя, то разбейте свою логику на несколько частей:

  1. Подтвердить личность
    Действие: Получить соответствующую строку пользователя из базы данных
    Результат:
    • Если такой строки не существует => неверный аккаунт
    • Если строка возвращается, перейдите к шагу 2.
  2. Проверка учетных данных
    Действие: Сравните сохраненные учетные данные (пароль, хэш пароля или зашифрованный пароль) с предоставленным паролем, обработанным так же, как хранятся учетные данные.
    Результат:
    • Нет совпадения => Неверный пароль / учетные данные
    • Match => Успешная попытка входа в систему
  3. Логин пользователя
    Действие: Добавить данные в сеанс и т. Д.
0 голосов
/ 11 сентября 2009

Вот что я придумал:

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'

Таким образом, я могу обнаружить в коде сообщения об ошибках и затем отобразить их при необходимости.

ПРИМЕЧАНИЕ: Всем, кто ссылается на проблемы безопасности с примером кода, спасибо за вашу заботу. Тем не менее, это не настоящий производственный код, это был простой пример, демонстрирующий мой вопрос. Совершенно очевидно, что вы не должны хранить пароли в виде открытого текста, и что вы не должны давать пользователям конкретные сведения о том, почему не удается войти в систему.

0 голосов
/ 11 сентября 2009

Вероятно, вам просто нужно разделить части предложения where с помощью 'AND'

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