- Los tokens de seguridad firman dentro del dispositivo sin exportar la clave privada fuera de él, y además requieren una acción física del usuario, lo que dificulta que un atacante remoto genere firmas arbitrarias
- Se pueden usar para autenticación SSH, U2F, inicio de sesión local sin contraseña,
sudo y firma de commits de git, y los dispositivos de seguridad integrados en laptops y smartphones modernos pueden sustituir a YubiKey
- El archivo de “clave privada” creado con
ssh-keygen -t ed25519-sk no es la clave privada real, sino un handle que apunta a la clave dentro del token, por lo que es posible generar el mismo archivo de clave SSH en otra computadora usando el mismo token
- En una MacBook fue posible configurar el secure element como clave SSH para habilitar el inicio de sesión SSH con Touch ID, y para firmar commits de git fue necesario usar
ssh-agent y un user.signingKey con formato key:: en lugar de una ruta de archivo
- Los tokens de seguridad no permiten recuperar la clave privada si se pierden y tienen un riesgo de usabilidad porque el usuario puede acostumbrarse a tocar repetidamente; en laptops con Windows, Windows Hello podía confirmar el uso de la clave SSH con reconocimiento facial, huella o PIN
Ventajas y límites de los tokens de seguridad
-
La estructura clave para detener ataques remotos
- Un token de seguridad mantiene el par de clave privada/pública dentro del dispositivo; la clave pública se puede extraer fácilmente, pero la clave privada no sale del dispositivo
- Si se envía al dispositivo el paquete de datos a firmar, este lo firma internamente con la clave privada y normalmente exige alguna acción física del usuario, como pulsar un botón táctil parpadeante
- Incluso si un atacante remoto obtiene acceso a la computadora, el token de seguridad no realizará firmas arbitrarias si el usuario no actúa físicamente en el mundo real, por lo que parece mejor que guardar el par completo de claves SSH privada/pública como archivos en el directorio
~/.ssh
- También hay opciones para quienes prefieren firmware FOSS, como SoloKeys y Nitrokeys
- Los tokens de seguridad más avanzados añaden autenticación biométrica, como un lector de huellas integrado, pero lo esencial es que la clave privada no pueda salir del dispositivo
-
Riesgos derivados de la usabilidad
- Si el usuario se acostumbra a pulsar el token de seguridad cada vez que parpadea, puede terminar respondiendo sin pensar incluso a solicitudes maliciosas
- Durante tareas de firma continuas en las que hay que tocar repetidamente el token, puede ser difícil notar de verdad una solicitud adicional que parpadee una vez más
- Apple y Microsoft usan en las apps de autenticación del smartphone un método que muestra un código numérico aleatorio por cada solicitud de acceso para que el usuario lo introduzca, pero esto es engorroso y reduce la ventaja de usabilidad de los tokens de seguridad frente a apps TOTP como Authy o Google Authenticator
-
Pérdida y respaldo
- Si se pierde un token de seguridad, esa clave privada desaparece para siempre y no hay forma de respaldarla
- Para evitar el riesgo de quedarse fuera de varias cuentas, al comprar un token de seguridad conviene adquirir al menos 2 y registrarlos en el mismo servicio
- Como alternativa, existen métodos de respaldo y recuperación como BIP 39, que convierten la clave privada en una lista de palabras legibles por humanos para anotarla
- Si la clave privada pudiera salir del secure enclave, también serían posibles ataques de phishing que induzcan al usuario a anotar esa lista de palabras en un lugar incorrecto
- Si realmente preocupa mucho la posibilidad de perder todos los tokens de seguridad, una lista de palabras BIP 39 puede ser el último recurso para recuperar el acceso al sistema
Uso de tokens de seguridad con SSH y git
-
Guardar la clave privada SSH en un token de seguridad
- Normalmente, al ejecutar
ssh-keygen se crea un par de archivos que incluye la clave privada completa
- Para guardar la clave privada en un token de seguridad, se instala libfido2 siguiendo la guía FIDO/U2F de Yubico, y luego se ejecuta
ssh-keygen -t ed25519-sk con el token conectado
- También en este caso se genera un par de archivos, pero el archivo de “clave privada” no es la clave privada real, sino un handle que apunta a la clave privada almacenada en el token de seguridad
- Si se ejecuta de nuevo
ssh-keygen -t ed25519-sk con el mismo token de seguridad, se pueden generar los mismos archivos de clave privada/pública en cualquier computadora, de modo que el acceso SSH se mueve con el token y no depende de un archivo específico en una máquina específica
-
Autenticación en git y firma de commits
- Aproximadamente el 90% de las veces que hay que tocar el token de seguridad es por usar git
- Los forges de git implementan autenticación SSH para operaciones de push y pull, y al subir el archivo
id_ed25519_sk.pub generado arriba pueden aceptar el par de claves del token de seguridad
- git también admite claves SSH para firma de commits; si se sigue la documentación de GitHub para configurar una clave de firma con una clave SSH y luego se ejecuta
git config --global commit.gpgsign true, todos los commits se firman automáticamente
- Para que el forge de git reconozca los commits como firmados por la misma persona, hay que volver a subir la clave pública, y este campo normalmente está separado del campo usado para autenticación SSH
-
Lo incómodo de la firma de commits
- Al hacer rebase de una lista larga de commits, hay que volver a firmarlos todos
- En una YubiKey con lector de huellas, la tasa de fallos del reconocimiento era demasiado alta para firmar decenas de commits seguidos, así que se dejó de usar
- jujutsu, un wrapper de git centrado en “rebase/amend”, tiene una forma de firmar commits solo al hacer push
-
Inicio de sesión local en Linux y sudo
Usar el secure element de una MacBook como clave SSH
- Si se deja siempre conectado un token de seguridad al puerto USB-C, queda sobresaliendo como una pequeña palanca que puede dañar tanto el puerto como el token si se golpea o se tira por accidente
- En una MacBook Air M1 de 2020 se configuró el elemento de seguridad integrado como clave SSH siguiendo la guía de Arian van Putten
sc_auth create-ctk-identity -l ssh -k p-256-ne -t bio
ssh-keygen -w /usr/lib/ssh-keychain.dylib -K -N ""
- Este comando creó el par de archivos de clave privada/pública
id_ecdsa_sk_rk, y luego esos archivos se movieron al directorio ~/.ssh
- También aquí el archivo de clave privada no es la clave privada real, sino un handle de la clave dentro del dispositivo, así que tiene una forma que se puede pegar públicamente
- Para agregar la clave pública como authorized key en un servidor del homelab, se ejecuta lo siguiente
ssh-copy-id -i ~/.ssh/id_ecdsa_sk_rk.pub <server nickname>
- Después se añade esta configuración a
~/.ssh/config
Host *
IdentityFile ~/.ssh/id_ecdsa_sk_rk
SecurityKeyProvider=/usr/lib/ssh-keychain.dylib
- Al ejecutar
ssh <server nickname>, macOS muestra automáticamente una solicitud de huella antes del inicio de sesión, y luego el acceso por SSH continúa normalmente
Firmar commits de git con el secure element de la MacBook
- Aunque se configure
git config --global user.signingKey /Users/ahelwer/.ssh/id_ecdsa_sk_rk y se actualice el archivo .ssh/allowed_signers, la firma de commits de git no funciona de inmediato
- git falla al firmar commits y muestra errores como
device not found?
error: Signing file /var/folders/l5/5wqvq2l10p96wtdtfr6lvrvw0000gn/T//.git_signing_buffer_tmpc4uQgO
Confirm user presence for key ECDSA-SK SHA256:oQDA2SNYb2MoSQcxJVSmWyAeAWPqMp7rxliBRfi87as
Couldn't sign message: device not found?
Signing /var/folders/l5/5wqvq2l10p96wtdtfr6lvrvw0000gn/T//.git_signing_buffer_tmpc4uQgO failed: device not found?
fatal: failed to write commit object
- La solución es usar ssh-agent en lugar de apuntar directamente a los archivos del directorio
~/.ssh
- Siguiendo el tutorial anterior, el par de claves se registra en ssh-agent con este comando
ssh-add -K -S /usr/lib/ssh-keychain.dylib
- Después, en
user.signingKey no se pone una ruta de archivo, sino la propia clave con el prefijo key:: delante del contenido de ~/.ssh/id_ecdsa_sk_rk.pub, dentro de ~/.gitconfig
[user]
name = Andrew Helwer
signingKey = "key::sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGxFEdnIg6ppz+pQCdd1eisjOV4gxrjMv1Y4SbtdLoSm6CJCgPZ6q7lnNyuQQsdnS4/Tllsc656AQL7BO3OS47cAAAAEc3NoOg== ssh:"
- Después de esta configuración, fue posible firmar archivos con la clave del secure element de la MacBook y hacer push al sitio de GitLab Pages
Resultados en Windows y Linux
- También se hizo una prueba rápida en una laptop Windows entregada por la empresa
winget install Microsoft.OpenSSH.preview
ssh-keygen -t ecdsa-sk
- Este comando también generó un par de archivos de clave privada/pública y, al conectarse por SSH, aceptó reconocimiento facial, huella o PIN mediante el flujo estándar de inicio de sesión de Windows Hello
- En Linux no se pudo hacer una demo porque no había acceso a una laptop con secure element que permitiera confirmar de forma similar la presencia real del usuario
1 comentarios
Opiniones en Lobste.rs
Es un gran artículo, y solo mostrar que esto es posible ya resulta muy útil
En lo personal, no logré encontrar la versión correcta de la biblioteca para hacer que esto funcionara, pero descubrí que 1Password 8 almacena claves SSH de forma segura y que el agente permite desbloquear la clave con autenticación biométrica
Así que ahora puedo trabajar con git e iniciar sesión en hosts SSH con solo poner el dedo
Guía: https://developer.1password.com/docs/ssh/get-started/
Esto parece ser solo para Mac
No he podido probar un sistema Linux con ese tipo de elemento de seguridad, y aunque mi estación de trabajo Linux tiene un TPM V1, no conozco una forma clara de garantizar que las operaciones de firma solo se ejecuten después de confirmar presencia real del usuario
Tal vez alguien con una laptop Linux como Framework podría intentarlo. Quizá incluso funcione de verdad en Asahi
Entonces, ¿qué contiene exactamente el archivo de clave privada que se proporciona?
ssh:, es decir, la aplicación, corresponde al origin del passkey y es útil al crear una resident key por host o dominioPor ejemplo, yo la uso para separar claves por propósito incluso dentro de la misma Yubikey física
flagsespecifica cómo el hardware debe tratar la clave [1]. El agente también puede agregar sus propias restriccionesTécnicamente, también se pueden guardar otros blobs o extensiones en una clave FIDO, y en un trabajo anterior lo usamos para pasar credenciales auxiliares junto con la autenticación, como una clave pública X.509. Es una forma bastante elegante de hacerlo
[1]
El envoltorio externo tiene el valor mágico
openssh-key-v1\0,cipher=none,kdf=none, así que no está cifradoEl blob de clave pública de 74 bytes contiene el tipo de clave
sk-ssh-ed25519@openssh.com, el punto Ed25519 de 32 bytesfdcce889…03e7852b, y la aplicaciónssh:, que separa por namespace las credenciales FIDO de SSH y WebAuthnLa sección privada tiene 248 bytes y, como
cipher=none, está en texto plano. Incluye el valor aleatoriocheckint1 == checkint2 == 0x46744267, el tipo de clave repetido y la clave pública, la aplicaciónssh:, yflags: 0x01Ese flag significa
USER_PRESENCE_REQUIRED, así que requiere toque pero no PIN ni verificación del usuario, y es una clave no residentekey_handlees un ID opaco de credencial de 128 bytes que se pasa aauthenticatorGetAssertion, y el dispositivo lo resuelve internamente para recuperar la semilla Ed25519Además de eso, hay un
reservedvacío, el comentarioahelwer@ah-mbair.local, y relleno01 02 03Este artículo parece tratar solo sobre SSH, pero ¿hay alguna forma de usar el Secure Enclave o el TPM de mi computadora como clave FIDO2 o U2F?
Los passkeys también son una forma de este enfoque, usando una clave privada distinta para cada sitio web
Viendo esto, se siente raro que no sea más común el soporte para claves API asimétricas o HMAC que puedan vincularse al hardware
Me alegra ver que van apareciendo más especificaciones que empujan en esa dirección, como WebAuthn, DBSC (Device-Bound Session Credentials) y OAuth2 DPOP