Cómo añadir el doble factor de autenticación (2FA) en la validación de usuario de una aplicación .Net C Sharp (C#), usando Google Authenticator. Mostramos todos los paquetes y componentes necesarios, así como el código fuente en C# para generar el código QR que el usuario escanea desde su app Google Authenticator en su móvil y también para verificar si una clave es correcta e incluso el código para generar varias claves offline, para cuando el usuario no tiene acceso a su app Google Authenticator.
- Qué es el doble factor de autenticación 2FA.
- Requisitos para añadir la opción de doble factor con Google Authenticator a una aplicación .Net C#.
- Crear proyecto Visual Studio 2022 C# con doble factor de autenticación 2FA de Google Authenticator.
- Agregar el paquete GoogleAuthenticator a nuestro proyecto .Net C#.
- Código fuente en C# completo para la aplicación que genera el código QR para Google Authenticator y realizar la validación de la clave y la generación de claves offline.
- La aplicación C# de doble factor con Google Authenticator en funcionamiento.
- Descarga de la aplicación ProyectoA 2FA Google Authenticator con código fuente completo C#.
Qué es el doble factor de autenticación 2FA
En el siguiente enlace explicamos en qué consiste la autentificación multifactor y, más concretamente, la autentificación de doble factor (2AF) o bien 2FA (Two-Factor Authentication):
En resumen, 2FA es la autenticación que combina dos de los métodos de verificación de identidad, por ejemplo, la petición de usuario y contraseña (algo que el usuario conoce) y una clave adicional generada desde el dispositivo móvil del usuario, por ejemplo con la App Google Authenticator (algo que el usuario posee).
Requisitos para añadir la opción de doble factor con Google Authenticator a una aplicación .Net C#
Necesitaremos disponer del IDE de desarrollo Visual Studio .Net . En el siguiente enlace explicamos cómo descargarlo e instalarlo:
Por otro lado, en el doble factor de autenticación con Google Authenticator, los usuarios de nuestra aplicación deberán descargarse e instalar la App Google Authenticator, que está disponible para dispositivos smartphones Android y iPhone. Esta aplicación será la que genere la clave que se le solicitará al usuario y que se irá modificando cada minuto.
En el caso de smartphones Android, se descargará e instalará desde Google Play:
En el primer inicio de Google Authenticator, nos solicitará que agreguemos una cuenta. Podemos hacerlo o bien escaneando un código QR o bien introduciendo los datos manualmente. En el caso de nuestra aplicación futura (como mostramos más adelante), se le mostrará al usuario un código QR para que lo escanee desde su móvil. Por lo tanto, el usuario elegirá la opción «Escanear un código QR»:
El usuario escaneará el código QR que se le mostrará en nuestra aplicación:
Se le creará una cuenta con los datos de la aplicación, en nuestro caso ProyectoA (ProyectoA_2FA_CSharp), pulsará en «Agregar cuenta»:
Y ya tendrá disponible en su móvil la app Google Authenticator y la cuenta para la aplicación. Cada vez que la aplicación le solicite la clave de doble factor de autenticación, el usuario accederá a su móvil, abrirá Google Autenticator e introducirá la clave que en ese momento le muestre para su cuenta (normalmente consistente en 6 números que irán cambiando cada minuto):
Crear proyecto Visual Studio 2022 C# con doble factor de autenticación 2FA de Google Authenticator
Desde Visual Studio 2022 pulsaremos en «Crear un proyecto»:
Elegiremos «Aplicación de Windows Forms» de .NET:
Introduciremos el nombre del proyecto, por ejemplo «ProyectoA_2FA_GoogleAuthenticator» y la carpeta donde se guardará el proyecto:
Elegiremos la versión de Framework a usar, por ejemplo «.NET 6.0» y pulsaremos en «Crear»:
Una vez creado el proyecto C# .Net, añadiremos un formulario principal con los siguientes componentes:
- TextBox para el nombre de la aplicación.
- TextBox para el editor (autor) de la aplicación.
- TextBox para la clave secreta. Muy importante no revelar esta clave dado que será la que se emplee para generar los códigos/claves de 2FA. Por ello, en la propiedad PasswordChar introduciremos un asterisco. En realidad, el único dato que Google Authenticator necesita es la clave secreta, a partir de ella podrá generar las claves de un solo uso para el 2FA. El resto de datos son descriptivos de la cuenta en la app Google Authenticator, para diferenciarla de otras que podamos tener.
- CheccBox para indicar si la clave secreta está en formato Base32 o no.
- Button para añadir el código fuente C# que generará el código QR para escanear y crear una cuenta en Google Authenticator.
- Button para permitir guardar el código QR generado en una imagen PNG. Este proceso es peligroso, dado que si un atacante tiene acceso a la imagen del código QR, podrá generar las claves de un solo uso. Por lo tanto, si lo usamos, debemos guardar la imagen en lugar seguro.
- PictureBox para mostrar el código QR con los datos necesarios para escanearlo desde el móvil y crear una cuenta en Google Authenticator.
- TextBox con Multiline = true, para mostrar los datos de la generación de la cuenta Google Authenticator. En este campo se mostrará también la URI necesaria para generar la cuenta completa en Google Authenticator. Por ello, hay que proceder con precaución con esta información, que un atacante podría usar para generar también claves de un solo uso al igual que el usuario. En caso de guardar la URI, lo haremos en un lugar seguro y nunca la expondremos públicamente.
- TextBox para comprobar que el procedimiento de validación 2FA con Google Authenticator funciona, donde se solicitará la clave de acceso que se mostrará en el móvil del usuario, en la app Google Authenticator.
- Button con el código fuente C# para verificar que la clave introducida es correcta. Si es correcta iniciaría sesión en la supuesta aplicación.
- Button para obtener listado de claves para cuando el usuario no tiene acceso a su móvil y su app Google Authenticator.
- TextBox con Multiline = true para mostrar las claves de 2FA generadas.
Quedando como se muestra a continuación:
En realidad, para añadir el 2FA a una aplicación real, únicamente tendríamos que solicitar al usuario la clave del doble factor en el formulario de inicio de sesión (clave de un solo uso, generada desde Google Authenticator), donde se le pedirá usuario y contraseña o bien otro medio de validación seguro. Y, la primera vez, se le mostrará el código QR para que lo escanee y quede registrada su cuenta en Google Authenticator (esto se mostrará una vez únicamente).
En el ejemplo que nos ocupa, para probar el doble factor, colocamos en el mismo formulario tanto la generación del código QR como la comprobación de la clave. Incluso permitimos que el usuario introduzca los datos de la aplicación, el autor y la clave secreta (cosa que en una aplicación real NO debemos mostrar ni permitir que se modifique).
Agregar el paquete GoogleAuthenticator a nuestro proyecto .Net C#
Para poder usar el 2FA en nuestra aplicación C#, utilizaremos el paquete GoogleAuthenticator. Para agregar este paquete a nuestro proyecto Visual Studio .Net, lo agregaremos o bien desde la consola visual o bien desde la línea de comandos. Desde la consola visual accederemos al menú «Proyecto» «Administrar paquetes NuGet…»:
En el administrador de paquetes NuGet buscaremos «GoogleAuthenticator» y lo instalaremos:
El asistente para instalar paquetes NuGet nos advertirá de que el paquete GoogleAuthenticator tiene las siguientes dependencias:
- Microsoft.Win32.SystemEvents.6.0.0.
- QRCoder.1.4.3.
- System.Drawing.Common.6.0.0.
Pulsaremos «OK» para instalar el paquete y sus dependencias:
El paquete quedará instalado y las librerías DLL necesarias quedarán agregadas a la carpeta del proyecto donde residirá el ejecutable:
- Google.Authenticator.dll
- QRCoder.dll
Estas librerías deben ir junto con el ejecutable de nuestra aplicación, o bien estar instaladas en el sistema, de lo contrario la aplicación no funcionará.
Código fuente en C# completo para la aplicación que genera el código QR para Google Authenticator y realizar la validación de la clave y la generación de claves offline
A continuación publicamos el código completo del formulario principal de la aplicación. En él está todo el código necesario para el funcionamiento de la aplicación:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
using Google.Authenticator; using System.Drawing.Imaging; namespace ProyectoA_GoogleAuthenticator { public partial class form2FAGoogleAuthenticator : Form { public form2FAGoogleAuthenticator() { InitializeComponent(); } private void bMostrarClaveSecreta_Click(object sender, EventArgs e) { if (txtClaveSecreta.PasswordChar == '*') txtClaveSecreta.PasswordChar = '\0'; else txtClaveSecreta.PasswordChar = '*'; } private void btVerificarClave2FAGoogleAuthenticator_Click(object sender, EventArgs e) { TwoFactorAuthenticator tfA = new TwoFactorAuthenticator(); //Verificamos que la clave introducida (generada desde la App del móvil Google Authenticator //Coincide con la calcula en base a la clave secreta (se tiene en cuenta si la clave está en Base32 o no) var resultadoValidacion2FA = tfA.ValidateTwoFactorPIN(txtClaveSecreta.Text, txtClave2FA.Text, opBase32.Checked); if (resultadoValidacion2FA) MessageBox.Show("Código correcto." + Environment.NewLine + Environment.NewLine + "Ya puede acceder a la aplicación.", "Resultado validación 2FA...", MessageBoxButtons.OK, MessageBoxIcon.Information); else MessageBox.Show("Código incorrecto." + Environment.NewLine + Environment.NewLine + "Revise el código que le proporciona " + "Google Authenticator en su dispositivo móvil.", "Resultado validación 2FA...", MessageBoxButtons.OK, MessageBoxIcon.Stop); } private void btObtenerClaveActual2FA_Click(object sender, EventArgs e) { //Obtiene varias claves válidas para cuando el usuario no tiene acceso a Google Authenticator //Tiene en cuenta si la clave secreta está en Base32 o no txtClaveActualGoogleAuthenticator.Text = string.Join(Environment.NewLine, new TwoFactorAuthenticator().GetCurrentPINs(txtClaveSecreta.Text, opBase32.Checked)); } private void btGenerarQR2FA_Click(object sender, EventArgs e) { string claveSecretaApp = txtClaveSecreta.Text; //Generamos el autenticador de doble factor, con el código QR incluido try { TwoFactorAuthenticator dobleFactor = new TwoFactorAuthenticator(); var infoDobleFactor = dobleFactor.GenerateSetupCode(txtEditor.Text, txtAplicacion.Text, claveSecretaApp, opBase32.Checked, 5); using (MemoryStream memStreamQR = new MemoryStream(Convert.FromBase64String( infoDobleFactor.QrCodeSetupImageUrl.Replace("data:image/png;base64,", "")))) qr2FAGoogleAutenticator.Image = Image.FromStream(memStreamQR); txtDatos2FA.Text = "Cuenta: " + infoDobleFactor.Account + Environment.NewLine + "Clave de codificación: " + infoDobleFactor.ManualEntryKey + Environment.NewLine + "URI: otpauth://totp/" + txtEditor.Text + ":" + txtAplicacion.Text + "?secret=" + infoDobleFactor.ManualEntryKey + "&issuer=" + txtEditor.Text; } catch (Exception ex) { MessageBox.Show("Error en la generación del código QR: " + Environment.NewLine + Environment.NewLine + ex.Message, "Error en QR...", MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void txtClave2FA_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { btVerificarClave2FAGoogleAuthenticator_Click(sender, e); } } private void btGuardarQR_Click(object sender, EventArgs e) { if (MessageBox.Show("Atención: proceda con precaución, si expone la imagen del " + "código QR, otro usuario podría agregar su cuenta con su clave secreta a" + " Google Authenticator ¿Desea continuar?", "Guardar QR en imagen...", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { SaveFileDialog dialogoGuardar = new SaveFileDialog(); dialogoGuardar.Filter = "Imagen PNG (*.png)|*.png"; dialogoGuardar.FilterIndex = 1; dialogoGuardar.RestoreDirectory = false; DialogResult resultadoDialogo = dialogoGuardar.ShowDialog(); if (resultadoDialogo == DialogResult.OK) qr2FAGoogleAutenticator.Image.Save(dialogoGuardar.FileName, ImageFormat.Png); } } private void txtAplicacion_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == '/') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = & y espacio", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (e.KeyChar == ':') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = & y espacio", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (e.KeyChar == '?') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = & y espacio", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (e.KeyChar == '=') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = & y espacio", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (e.KeyChar == '&') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = & y espacio", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (e.KeyChar == ' ') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = & y espacio", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } private void txtEditor_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == '/') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = &", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (e.KeyChar == ':') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = &", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (e.KeyChar == '?') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = &", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (e.KeyChar == '=') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = &", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } if (e.KeyChar == '&') { e.Handled = true; MessageBox.Show("Caracteres no permitidos: / : ? = &", "Carácter no permitido...", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } } } } |
La aplicación C# de doble factor con Google Authenticator en funcionamiento
Compilando la aplicación C#, nos mostrará el formulario principal de ejemplo para, en primer lugar, generar el QR a partir de los datos básicos:
- Nombre aplicación [1]: introduciremos el nombre de la aplicación, sin espacios. Este dato, en una aplicación real, no se mostraría al usuario ni se le daría la opción de modificarlo.
- Editor (autor) [2]: introduciremos el nombre de la organización (por ejemplo). Al igual que en el caso anterior, en una aplicación real, no se mostraría al usuario ni se le daría la opción de modificarlo.
- Clave secreta [3]: esta clave secreta será la que se le asigne al usuario para nuestra aplicación. En una aplicación real, esta clave secreta NO se mostrará al usuario. A cada usuario de la aplicación se le asignará una clave secreta segura y única. Para esta aplicación de ejemplo, se permite agregar una clave secreta cualquiera. Lo habitual será guardar esta clave secreta cifrada en base de datos, por ejemplo, asociada al usuario. De esta forma, si el usuario pierde el autentificador en Google Authenticator, se le podría ofrecer la posibilidad de volver a generar el QR y su cuenta de Google Authenticator.
- Si la clave la hemos introducido en formato Base32 marcaremos el check «Base32» [4]. Si, por el contrario, hemos introducido la clave secreta en real, del tipo MiContraseñaSecreta4670##$, no marcaremos el check. Es importante marcarlo sólo cuando la clave viene dada en Base32, de lo contrario no funcionará el proceso.
Una vez introducidos los datos anteriores, se pulsará en «Generar QR para cuenta Google Authenticator» [5]:
La aplicación generará el código QR que el usuario puede escanear desde su móvil, para agregar su cuenta Google Authenticator para nuestra aplicación. También mostrará los datos en «Datos 2FA», entre ellos, la URI necesaria (que podemos copiar) para generar la cuenta en Google Authenticator. Por lo tanto, procederemos con mucha precaución, dado que si un atacante consigue esta URI, podrá generar también las claves de un solo uso. Esta URI no debe guardarse ni exponerse públicamente, es confidencial, es secreta, al igual que la clave secreta.
A modo de ejemplo, la aplicación también permite verificar una clave. El usuario abrirá Google Authenticator desde su móvil, e introducirá la clave generada para nuestra aplicación. Introducirá la clave en «Introduzca clave Google Authenticator» [1] y comprobará si es correcta pulsando en «Verificar clave» [2]:
Si es correcta nos lo indicará con:
En caso de no ser correcto, nos mostrará:
Por último, la aplicación también permite generar 20 claves que servirán al usuario para cuando no tenga acceso al móvil o a Google Authenticator, son claves temporales:
Descarga de la aplicación ProyectoA 2FA Google Authenticator con código fuente completo C#
A continuación se muestra el enlace para la descarga del proyecto completo en Visual Studio 2022 C# de la aplicación ProyectoA 2FA Google Authenticator: