Añadir un segundo factor a un script de inicio de sesión

CiberseguridadBeginner
Practicar Ahora

Introducción

La autenticación multifactor reduce el riesgo de compromiso de cuentas al requerir más de un tipo de prueba. Una contraseña es algo que el usuario conoce. Un segundo factor puede ser un código proveniente de un dispositivo, aplicación, archivo o token de hardware independiente.

En este laboratorio, comenzará con un script de inicio de sesión en Python que solo utiliza contraseña y luego añadirá un segundo factor sencillo. Para mantener el laboratorio accesible para principiantes y determinista, el segundo factor será un código basado en HMAC generado a partir de un archivo secreto protegido.

Probar el inicio de sesión solo con contraseña

En este paso, ejecutará el script de inicio de sesión inicial. Este solo verifica un nombre de usuario y una contraseña, lo cual constituye una autenticación de factor único, ya que la única prueba es algo que el usuario conoce.

Acceda al directorio del proyecto:

cd /home/labex/project

Inspeccione los archivos preparados:

ls -l

Visualice la base de datos de usuarios:

cat users.json

Ejecute un inicio de sesión exitoso solo con contraseña:

python3 login.py alice wonderland

La salida debería ser:

login ok

Ahora intente con una contraseña incorrecta:

python3 login.py alice wrong

Este comando debería imprimir login failed. Un inicio de sesión fallido termina con un estado distinto de cero, lo cual es normal para esta prueba.

Ejecute el verificador para el estado inicial:

python3 mfa-check.py password-only

El resultado esperado es:

password-only: complete

Crear el secreto para el segundo factor

En este paso, creará un secreto independiente para el segundo factor. En un sistema MFA real, este secreto podría residir en una aplicación de autenticación o en un token de hardware. En este laboratorio, se trata de un archivo local para que el comportamiento sea fácil de inspeccionar y verificar.

Cree un valor secreto:

printf 'labex-mfa-secret-2026\n' > mfa_secret.txt

Restrinja el archivo para que solo el propietario pueda leerlo y escribirlo:

chmod 600 mfa_secret.txt

Compruebe los permisos:

ls -l mfa_secret.txt

Los bits de permiso deberían comenzar con -rw-------:

-rw------- ... mfa_secret.txt

Ejecute el verificador para el secreto:

python3 mfa-check.py secret

El resultado esperado es:

secret: complete

Generar un código de inicio de sesión

En este paso, creará un pequeño generador de códigos. Utiliza HMAC-SHA256 para combinar el archivo secreto con el nombre de usuario. HMAC es útil aquí porque la misma entrada y el mismo secreto producen el mismo código corto, pero alguien sin el secreto no puede crear el código fácilmente.

Cree generate-code.py:

cat > generate-code.py <<'PY'
#!/usr/bin/env python3
import hmac
import hashlib
import sys
from pathlib import Path

if len(sys.argv) != 2:
    print("usage: generate-code.py USERNAME")
    raise SystemExit(2)

username = sys.argv[1]
secret = Path("mfa_secret.txt").read_text().strip().encode()
digest = hmac.new(secret, username.encode(), hashlib.sha256).hexdigest()
print(digest[:6])
PY

Hágalo ejecutable:

chmod +x generate-code.py

Genere un código para alice:

python3 generate-code.py alice

Debería ver este código determinista de seis caracteres:

21f18f

Ejecute el verificador para el generador:

python3 mfa-check.py generator

El resultado esperado es:

generator: complete

Aplicar el segundo factor

En este paso, reemplazará el script de inicio de sesión para que requiera tanto la contraseña como el código generado. Este es el cambio clave de MFA: la contraseña por sí sola ya no es suficiente.

Reemplace login.py con esta versión compatible con MFA:

cat > login.py <<'PY'
#!/usr/bin/env python3
import hmac
import hashlib
import json
import sys
from pathlib import Path

USERS = Path("users.json")
SECRET = Path("mfa_secret.txt")

def expected_code(username):
    secret = SECRET.read_text().strip().encode()
    digest = hmac.new(secret, username.encode(), hashlib.sha256).hexdigest()
    return digest[:6]

def main():
    if len(sys.argv) != 4:
        print("usage: login.py USERNAME PASSWORD MFA_CODE")
        return 2

    username, password, code = sys.argv[1], sys.argv[2], sys.argv[3]
    users = json.loads(USERS.read_text())
    if users.get(username, {}).get("password") != password:
        print("login failed")
        return 1

    if not hmac.compare_digest(code, expected_code(username)):
        print("mfa failed")
        return 1

    print("login ok")
    return 0

if __name__ == "__main__":
    raise SystemExit(main())
PY

Asegúrese de que el script sea ejecutable:

chmod +x login.py

Genere un código nuevo y guárdelo en una variable de shell:

CODE="$(python3 generate-code.py alice)"

Utilice la contraseña y el código correctos juntos:

python3 login.py alice wonderland "$CODE"

La salida debería ser:

login ok

Ejecute el verificador para la aplicación de MFA:

python3 mfa-check.py enforced

El resultado esperado es:

enforced: complete

Probar el fallo y el éxito de MFA

En este paso, probará el comportamiento final del inicio de sesión. Una contraseña correcta sin el segundo factor debería fallar, un código incorrecto debería fallar, y la contraseña correcta junto con el código correcto deberían tener éxito.

Primero, intente el comando antiguo de solo contraseña:

python3 login.py alice wonderland || true

La salida debería mostrar el nuevo mensaje de uso porque falta el código MFA:

usage: login.py USERNAME PASSWORD MFA_CODE

Intente con un código incorrecto:

python3 login.py alice wonderland 000000 || true

La salida debería ser:

mfa failed

Genere el código correcto e inicie sesión:

CODE="$(python3 generate-code.py alice)"
python3 login.py alice wonderland "$CODE"

La salida debería ser:

login ok

Ejecute el verificador completo:

python3 mfa-check.py all

La salida final debería mostrar que todos los componentes de MFA están completos:

secret: complete
generator: complete
enforced: complete

Resumen

Ha transformado un script de inicio de sesión basado solo en contraseña en un flujo de inicio de sesión multifactor sencillo. Creó un secreto MFA independiente, generó un código basado en HMAC, exigió dicho código en el script de inicio de sesión y probó tanto los casos de fallo como los de éxito.

El concepto de seguridad principal es que una contraseña robada no debería ser suficiente por sí sola cuando se requiere una segunda prueba independiente.