2009-09-11 4 views
3

Допустим, у меня есть SQL заявление, как это, который проверяет логин пользователя:определить, какая часть (ы) ГДЕ Заявление Failed

SELECT * FROM users 
WHERE username='[email protected]', password='abc123', expire_date>=NOW(); 

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

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

Для моих целей я использую PHP/MySQL.

+1

Временная часть expire_date может быть меньше того, что возвращается в NOW(), в результате чего запрос не возвращает ожидаемые результаты. –

+0

Спасибо, я понимаю, что поле хранит время, хотя имя немного вводит в заблуждение. – macinjosh

+3

Вы собираетесь передать причину отказа пользователю? Это может облегчить доступ хакерам. –

ответ

0

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

SELECT 
    IF(mem_username='[email protected]','true','Error: Bad Username') AS mem_username, 
    IF(mem_password ='abc123','true','Error: Bad Password') AS mem_password' 
FROM MEMBERS 
WHERE mem_username='[email protected]m' AND mem_password='abc123' 

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

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

+0

Не помогайте хакерам, сообщая им, что они неверно получили имя пользователя и пароль! Также см. Ответы других пользователей о том, что вы не храните пароли в ящике в своей базе данных !!! –

+0

Этот SQL очень ханкий; Во-первых, плохо планировать повторять имя поля как псевдоним; Во-вторых, он никогда не даст вам сообщение об ошибке - предложение WHERE будет только возвращать записи, которые делают оба предложения IF истинными; В-третьих, тест «плохое имя пользователя» выглядит странно; вы действительно хотите сказать кому-то «у вас есть правильный пароль, но для другого пользователя»? Я предлагаю Выбирается, если (mem_password_hash = 'c0e1732fa', правда, ложь) от членов ГДЕ mem_username='[email protected]» Вы уже знаете имя пользователя; если он возвращает true, они передаются, false означает неверный пароль, NULL означает «плохое имя пользователя». –

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' 
+0

Решение SQL только было бы идеальным из-за нашей текущей структуры кода. – macinjosh

+1

Это рекомендуемый подход. Извлеките пользовательскую строку на основе имени (если нет пользователя), сравните хеш-пароль (если вы ошиблитесь с неверным паролем), последний сохраните идентификатор строк (идентификатор пользователя) и все остальное в сеансе и запишите их. – Xeoncross

1

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

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

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

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

В моем конкретном случае мы хочу сообщить пользователю эту информацию. Мы учли риски безопасности. – macinjosh

+0

этот (и счет) все еще лучший ответ. просто потому, что ваш запрос возвращает результат, не означает, что вы действительно передаете всю эту информацию пользователю. – longneck

+0

Правильно, согласен. Не нужно раскрывать причину сбоя auth. Но разработчик может все еще хотеть узнать о повторных неудачных паролях для данной учетной записи пользователя, например, для установления блокировки. –

0

Вы, наверное, просто нужно отделить части от где п с «И»

SELECT * FROM users 
WHERE username='[email protected]' 
    And password='abc123' 
    And expire_date>=NOW(); 
4

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

SELECT password = 'abc123' AS is_authenticated, 
     expire_date >= NOW() AS is_not_expired 
FROM users 
WHERE username='[email protected]'; 

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

PS: Это касание вашего вопроса, но я призываю вас не хранить пароли в открытом виде. Сохраните хеш-дайджест соленого пароля. См How does password salt help against a rainbow table attack?

+0

спасибо за вашу заботу о моей безопасности, это был просто примерный запрос, а не реальная вещь! Я согласен, хеши - это обязательно! – macinjosh

+0

Хорошо, круто, я подумал, что ваш запрос был упрощен от реальной вещи, но я хотел бы обязательно упомянуть хэширование на всякий случай. :) –