getpass: lee contraseñas en terminal con Python

Actualizado el: 21/08/2026
Tempo de leitura: 5 minutos
Leitura segura de senhas no terminal usando Python

Leer una contraseña desde el terminal parece una tarea sencilla, pero utilizar input() muestra cada carácter en la pantalla y puede dejar información sensible visible para otras personas, grabaciones o historiales de sesión. Python incluye el módulo getpass, diseñado para solicitar secretos sin mostrarlos mientras el usuario escribe. Esta solución mejora la privacidad de la entrada, aunque no sustituye el almacenamiento seguro, el cifrado de conexiones ni una política de autenticación completa.

Antes de continuar conviene revisar la función input(), el manejo de excepciones, las funciones en Python, la guía de hashing de contraseñas con bcrypt y el uso de variables de entorno con python-dotenv.

Las referencias externas principales son la documentación oficial del módulo getpass y la guía de autenticación de OWASP, que explica controles adicionales para sistemas reales.

Por qué input() no es apropiado para contraseñas

usuario = input("Usuario: ")
contrasena = input("Contraseña: ")

Este código funciona, pero la contraseña queda visible. Al compartir pantalla, grabar una demostración o trabajar en un espacio público, el secreto puede quedar expuesto. Además, algunas terminales conservan texto copiado o permiten revisar el contenido visual anterior.

Solicitar una contraseña con getpass

from getpass import getpass

usuario = input("Usuario: ").strip()
contrasena = getpass("Contraseña: ")

print(f"Usuario recibido: {usuario}")

Mientras el usuario escribe, normalmente no aparece ningún carácter. Esto es diferente de mostrar asteriscos: la implementación estándar suele ocultar completamente la entrada. No imprimas después la variable ni la incluyas en mensajes de depuración.

Crear una función de lectura

from getpass import getpass


def leer_contrasena(mensaje="Contraseña: "):
    valor = getpass(mensaje)
    if not valor:
        raise ValueError("La contraseña no puede estar vacía")
    return valor

Separar la lectura permite reutilizar la validación y probar la lógica que procesa el resultado. La función devuelve un string; no convierte ni cifra automáticamente su contenido.

Confirmar la contraseña

def solicitar_nueva_contrasena():
    primera = getpass("Nueva contraseña: ")
    segunda = getpass("Repite la contraseña: ")

    if primera != segunda:
        raise ValueError("Las contraseñas no coinciden")
    if not primera:
        raise ValueError("La contraseña no puede estar vacía")
    return primera

La comparación confirma que el usuario no cometió un error de escritura. En una interfaz real, limita los intentos y proporciona mensajes claros sin revelar detalles innecesarios.

Validar longitud y calidad básica

def validar_contrasena(valor):
    errores = []

    if len(valor) < 12:
        errores.append("Debe tener al menos 12 caracteres")
    if valor.lower() == valor:
        errores.append("Debe incluir una mayúscula")
    if valor.upper() == valor:
        errores.append("Debe incluir una minúscula")
    if not any(c.isdigit() for c in valor):
        errores.append("Debe incluir un número")

    return errores

Estas reglas son un ejemplo educativo. Las políticas modernas suelen favorecer contraseñas largas y permitir frases de paso, en lugar de imponer combinaciones demasiado rígidas. También deben bloquearse contraseñas comprometidas y aplicarse límites de intentos.

Crear un flujo interactivo robusto

def crear_contrasena(max_intentos=3):
    for intento in range(1, max_intentos + 1):
        primera = getpass("Nueva contraseña: ")
        segunda = getpass("Confirmación: ")

        if primera != segunda:
            print("Las contraseñas no coinciden")
            continue

        errores = validar_contrasena(primera)
        if errores:
            print("No cumple los requisitos:")
            for error in errores:
                print(f"- {error}")
            continue

        return primera

    raise RuntimeError("Se superó el número de intentos")

El límite impide un bucle sin fin. No incluyas la contraseña en el mensaje de error, logs o excepciones.

No almacenar contraseñas en texto plano

Ocultar la entrada solo protege el momento de escritura. Si guardas el valor directamente, cualquier persona con acceso al archivo podrá leerlo:

# No recomendado
with open("usuarios.txt", "w", encoding="utf-8") as archivo:
    archivo.write(contrasena)

Para autenticar usuarios, almacena un hash lento y diseñado para contraseñas, como bcrypt, Argon2 o scrypt. Un hash no es cifrado reversible: el sistema verifica si una contraseña produce un resultado compatible, sin necesitar recuperar el texto original.

Ejemplo con bcrypt

import bcrypt
from getpass import getpass

contrasena = getpass("Nueva contraseña: ").encode("utf-8")
hash_guardado = bcrypt.hashpw(contrasena, bcrypt.gensalt())

intento = getpass("Contraseña para acceder: ").encode("utf-8")

if bcrypt.checkpw(intento, hash_guardado):
    print("Acceso permitido")
else:
    print("Credenciales inválidas")

No uses SHA-256 directamente para contraseñas, porque es demasiado rápido y facilita ataques masivos. Una biblioteca especializada gestiona el salt y el coste computacional.

Evitar secretos en argumentos de línea de comandos

# Evita ejecutar algo como:
# python programa.py --password mi_secreto

Los argumentos pueden aparecer en el historial del shell o en la lista de procesos. Para un secreto introducido por una persona, getpass es preferible. Para credenciales de servicios, usa un gestor de secretos o variables de entorno protegidas, según el contexto.

Usar getuser para conocer el usuario del sistema

from getpass import getuser

print(getuser())

getuser() intenta obtener el nombre del usuario del entorno. No lo trates como autenticación: es información del sistema local y puede no representar una identidad verificada.

Manejar terminales incompatibles

En algunos entornos interactivos, notebooks, IDEs o terminales redirigidas, getpass puede emitir una advertencia y no ocultar la entrada como se espera. La documentación oficial describe GetPassWarning. Puedes tratarla explícitamente:

from getpass import GetPassWarning, getpass
import warnings

with warnings.catch_warnings():
    warnings.simplefilter("error", GetPassWarning)
    try:
        secreto = getpass("Secreto: ")
    except GetPassWarning:
        raise RuntimeError("La terminal no permite ocultar la entrada")

Es mejor detener el proceso que solicitar un secreto de forma visible sin avisar.

No registrar el contenido sensible

import logging

logging.info("Intento de autenticación recibido")
# Nunca hagas: logging.info("Contraseña: %s", contrasena)

Los logs suelen copiarse a servidores, sistemas de observabilidad y copias de seguridad. Incluso un entorno de desarrollo puede conservarlos durante meses.

Reducir la permanencia en memoria

En Python, los strings son inmutables y no existe una garantía sencilla de borrar inmediatamente todas las copias de una contraseña en memoria. Evita duplicar el valor, formatearlo en otros strings o mantenerlo en variables globales. Úsalo durante el menor tiempo posible y delega la autenticación a bibliotecas confiables.

Ejemplo de inicio de sesión local

import bcrypt
from getpass import getpass

HASH_ESPERADO = b"$2b$12$..."  # Cargar desde almacenamiento seguro


def autenticar():
    usuario = input("Usuario: ").strip()
    intento = getpass("Contraseña: ").encode("utf-8")

    usuario_valido = usuario == "admin"
    contrasena_valida = bcrypt.checkpw(intento, HASH_ESPERADO)

    if usuario_valido and contrasena_valida:
        print("Acceso permitido")
        return True

    print("Credenciales inválidas")
    return False

El mensaje no indica si falló el usuario o la contraseña, lo que reduce información útil para un atacante. Un sistema real necesita protección contra fuerza bruta, sesiones seguras, recuperación de cuenta y autenticación multifactor.

Pruebas sin escribir contraseñas reales

La validación debe probarse con valores ficticios. Separa la entrada de la lógica:

def credencial_valida(usuario, intento, hash_esperado):
    return usuario == "admin" and bcrypt.checkpw(
        intento.encode("utf-8"),
        hash_esperado,
    )

Así los tests pueden usar hashes creados específicamente para pruebas. Nunca copies credenciales de producción en el repositorio.

Errores frecuentes

Los problemas más comunes son usar input(), imprimir la contraseña para depurar, guardarla en texto plano, enviarla como argumento del terminal, registrar excepciones con datos sensibles y creer que ocultar la escritura resuelve toda la seguridad. También es un error inventar un algoritmo de hash propio.

Conclusión

getpass es la herramienta estándar para leer contraseñas sin mostrarlas en el terminal. Combínala con validación, límites de intentos, hashing especializado y mensajes de error discretos. Mantén los secretos fuera de logs, argumentos y repositorios. La entrada oculta es solo una capa; la seguridad real depende de todo el ciclo de autenticación y almacenamiento.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Configuración TOML en un proyecto Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    tomllib en Python: lee archivos TOML

    Aprende a leer TOML con tomllib en Python, validar configuraciones, gestionar errores y organizar proyectos con pyproject.toml.

    Ler mais

    Tempo de leitura: 6 minutos
    24/07/2026
    Desarrollador monitoreando registros estructurados en Python
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Observabilidad en Python con structlog

    Aprende observabilidad en Python con structlog, eventos JSON, contexto, pruebas, control de volumen y recomendaciones para producción.

    Ler mais

    Tempo de leitura: 5 minutos
    24/07/2026
    Configuración segura de aplicaciones Python con Pydantic Settings
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Pydantic Settings: configuración segura

    Aprende a validar variables de entorno, organizar configuraciones y proteger secretos en proyectos Python con Pydantic Settings.

    Ler mais

    Tempo de leitura: 5 minutos
    23/07/2026
    Desenvolvedor programando em Python com Ruff para lint e formatação
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Ruff: lint y formato de código Python

    Aprende Ruff en Python para lint, formato, correcciones automáticas, pyproject.toml, VS Code y CI con una configuración práctica.

    Ler mais

    Tempo de leitura: 10 minutos
    22/07/2026
    Dicas para melhorar performance de scripts Python lentos
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    ¿Por qué Python es lento? Causas y optimización

    Descubre por qué Python puede ser lento y mejora su rendimiento con cProfile, algoritmos, sets, generadores, NumPy, caché y concurrencia.

    Ler mais

    Tempo de leitura: 5 minutos
    12/07/2026
    Exemplo de testes unitários em Python com código de unittest para validação automatizada
    Buenas Prácticas
    Foto de perfil de Leandro Hirt da Academify

    Tests unitarios en Python: unittest, pytest y mocks

    Aprende tests unitarios en Python con unittest, pytest, fixtures, parametrización, mocks, cobertura y buenas prácticas para evitar regresiones.

    Ler mais

    Tempo de leitura: 5 minutos
    11/07/2026