Pregunta

Digamos que tengo una instrucción SQL como esta que verifica el inicio de sesión de un usuario:

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

¿Hay alguna forma en SQL para determinar específicamente qué WHERE fallan las condiciones, sin tener que separar cada condición en su propia consulta y probar individualmente?

En este ejemplo específico, permitiría al desarrollador decirles a los usuarios exactamente la razón por la cual su intento de inicio de sesión falló.

Para mis propósitos, estoy usando PHP / MySQL.

¿Fue útil?

Solución 5

Esto es lo que se me ocurrió:

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'

De esta forma puedo detectar en el código los mensajes de error y luego mostrarlos según sea necesario.

NOTA : A todos ustedes citando preocupaciones de seguridad con el código de ejemplo, gracias por su preocupación. Sin embargo, este no es un código de producción real, fue simplemente un ejemplo simple para demostrar la pregunta que tenía. Es bastante obvio que no debe almacenar las contraseñas en texto claro, y que no debe dar a los usuarios detalles sobre por qué falla el inicio de sesión.

Otros consejos

Bueno, una cosa que podría hacer es cambiar su consulta para que solo coincida con el nombre de usuario. Luego, en el código, verifica la contraseña y la fecha de vencimiento, devolviendo los errores apropiados.

Además, espero que su consulta de ejemplo sea una simplificación; Ciertamente, debería estar usando sal / encriptación / hash de sus contraseñas, y debe incluir algo que limite el número de intentos fallidos dentro de un cierto período de tiempo, etc ...

En cuanto a su pregunta real (a diferencia de los resultados que está buscando), no hay una manera de obtener esa información de la cláusula where. Lo más cercano que podría hacer sería 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'

En MySQL puede poner expresiones booleanas en la lista de selección. Las expresiones booleanas evalúan el entero 1 cuando es verdadero, o el entero 0 cuando es falso.

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

nota: si necesita escribir una consulta que funcione en otras marcas de RDBMS, tenga en cuenta que este uso de expresiones booleanas no es estándar. Use la sintaxis CASE que otras personas han publicado.

PD: Esta es una tangente de su pregunta, pero le insto a que no almacene contraseñas en texto sin formato. Almacene un resumen de hash de la contraseña salada. Consulte ¿Cómo ayuda la sal de contraseña contra un ataque de mesa arcoiris?

No, la cláusula where se aplica como un bloque y se utilizan varias técnicas para que no se tengan que escanear todas las filas. Además, ¿cómo podría saber qué fila era la que deseaba?

Además, probablemente no desee decirle demasiado al usuario por qué falló un intento de inicio de sesión. Decir demasiado permite explotaciones como minería de cuentas y ataques de contraseña.

editar Si realmente desea mostrar esto a su usuario, divida su lógica en diferentes partes:

  1. Validar identidad
    Acción: recuperar la fila de usuario correspondiente de la base de datos
    Resultado:
    • Si no existe tal fila = > cuenta inválida
    • Si se devuelve la fila, continúe con el paso 2.
  2. Validar credencial
    Acción: compruebe la credencial almacenada (contraseña, hash de contraseña o contraseña cifrada) con la contraseña suministrada tratada de la misma manera que se almacena la credencial.
    Resultado:
    • Sin coincidencia = > Contraseña / credencial no válida
    • Match = > Intento de inicio de sesión exitoso
  3. Usuario de inicio de sesión
    Acción: Agregar datos a la sesión, etc.

Probablemente solo necesite separar las partes de la cláusula where con 'AND'

SELECT * FROM users 
WHERE username='test@example.com'
   And password='abc123'
   And expire_date>=NOW();
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top