Determinar qual peça (s) de instrução WHERE Falha
-
05-07-2019 - |
Pergunta
Vamos dizer que eu tenho uma instrução SQL como esta que verifica um login de usuário:
SELECT * FROM users
WHERE username='test@example.com', password='abc123', expire_date>=NOW();
Existe uma maneira no SQL para determinar especificamente quais condições WHERE falhar, sem ter que separar cada condição em sua própria consulta e teste individualmente?
Neste exemplo específico seria permitir que o desenvolvedor para informar aos usuários exatamente a razão pela qual a sua tentativa de login falhou.
Para os meus propósitos que estou usando PHP / MySQL.
Solução 5
Aqui está o que eu vim com:
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'
Esta maneira que eu possa detectar no código para mensagens de erro e, em seguida, exibi-los quando necessário.
NOTA: A todos vós citando preocupações de segurança com o código de exemplo, muito obrigado pela sua preocupação. No entanto, este não é o código de produção real, isso era simplesmente um exemplo simples para demonstrar a pergunta que eu tinha. É bastante óbvio que você não deve armazenar senhas em texto claro, e que você não deve dar aos usuários detalhes sobre o porquê de login falhar.
Outras dicas
Bem, uma coisa que você poderia fazer é alterar a sua consulta para que ele corresponde apenas no nome do usuário. Em seguida, o código que você verificar a senha ea data de validade, retornando erros apropriados.
Além disso, eu espero que o seu exemplo de consulta é uma simplificação; Certamente você deve ser salga / criptografar / hash de suas senhas, e você deve incluir algo que limita o número de tentativas falhadas dentro de um determinado período de tempo, etc ...
Quanto a sua pergunta real (em oposição aos resultados que você está procurando), não há uma maneira de obter essa informação a partir da cláusula WHERE. O mais próximo que você poderia fazer seria algo como:
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'
No MySQL você pode colocar expressões booleanas na lista de seleção. expressões booleanas avaliar para o número inteiro 1, quando verdadeiro, ou o número inteiro 0, quando falsa.
SELECT password = 'abc123' AS is_authenticated,
expire_date >= NOW() AS is_not_expired
FROM users
WHERE username='test@example.com';
Nota: Se você precisa escrever uma consulta que funciona em outras marcas de RDBMS, tenha em mente que este uso de expressões booleanas é fora do padrão. Use a sintaxe CASE
que outras pessoas postaram.
PS: Esta é uma tangente de sua pergunta, mas peço-lhe para não armazenar senhas em texto simples. Armazenar um hash digerir da senha salgada. Consulte Como é que ajuda sal senha contra um ataque tabela arco-íris?
Não, o onde cláusula é aplicada como um bloco, e várias técnicas são usadas de modo que nem todas as linhas têm de ser digitalizado. Além disso, como você sabe qual linha foi o que foi desejado?
Além disso, você provavelmente não quer dizer que o usuário muito sobre por que uma tentativa de login falhou. Dizer muito permite façanhas como ataques conta de mineração e senha.
Editar Se você realmente quer mostrar isso ao seu usuário, em seguida, dividir sua lógica em diferentes partes:
- identidade Validar
Ação: Retorna a linha do usuário correspondente do banco de dados
Resultado:- Se não existirem linha => conta inválido
- Se linha é retornada, continue para o passo 2.
- Validar credencial
Ação: Verifique a credencial armazenada (senha, hash da senha ou senha criptografada) contra a senha fornecida tratados da mesma forma a credencial é armazenada.
Resultado:- No match => Senha inválida / credencial
- Jogo => tentativa de login bem-sucedida
- user Entrada
Ação:. Adicionar dados a sessão etc
Você provavelmente só precisa separar as partes da cláusula WHERE com 'E'
SELECT * FROM users
WHERE username='test@example.com'
And password='abc123'
And expire_date>=NOW();