autentificacion-en-esp32

Qué es y cómo usar autentificación en ESP32

La autentificación es un proceso fundamental en cualquier sistema de comunicación, incluidos los que hagamos con un ESP32.

Consiste en verificar la identidad de un usuario, dispositivo o entidad antes de permitirle el acceso a un recurso o servicio.

En cualquier proyecto que pretendamos exponer al público, la autentificación es imprescindible para proteger nuestras comunicaciones, datos y sistemas contra accesos no autorizados.

Así que vamos a ver los distintos métodos que tenemos disponibles para implementarla en un dispositivo como el ESP32.

La autentificación suele combinarse con otros mecanismos de seguridad, como la encriptación, para garantizar la integridad y confidencialidad de los datos.

Tipos de autentificación en el ESP32

En el ESP32, podemos implementar varios métodos de autentificación, dependiendo de los requisitos del sistema y de nuestro proyecto:

  • Autentificación basada en contraseñas: El método más común, donde un usuario o dispositivo proporciona una contraseña para verificar su identidad.
  • Autentificación basada en tokens: Utiliza tokens temporales (como JWT) para validar la identidad.
  • Autentificación de dispositivos mediante certificados: Emplea certificados digitales para verificar la identidad de un dispositivo.
  • Autentificación de mensajes: Asegura que los mensajes provienen de una fuente confiable mediante firmas digitales.

A continuación, vamos a ver cómo implementar cada uno de estos métodos en el ESP32.

Autentificación basada en contraseñas

La autentificación basada en contraseñas es el método más sencillo y ampliamente utilizado. Consiste en comparar una contraseña proporcionada por el usuario con una almacenada en el sistema.

Para implementar este método, podemos almacenar una contraseña en la memoria del ESP32 (por ejemplo, en la EEPROM o en la memoria flash) y compararla con la entrada del usuario.

#include <WiFi.h>

const char* ssid = "TuRedWiFi";
const char* password = "TuContraseñaWiFi";

String contraseñaAlmacenada = "secreto123"; // Contraseña almacenada

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Conectando a WiFi...");
  }
  Serial.println("Conectado a WiFi");
}

void loop() {
  if (Serial.available()) {
    String contraseñaIngresada = Serial.readString(); // Leer la contraseña ingresada
    contraseñaIngresada.trim(); // Eliminar espacios en blanco

    if (contraseñaIngresada == contraseñaAlmacenada) {
      Serial.println("Autentificación exitosa");
    } else {
      Serial.println("Autentificación fallida");
    }
  }
}
  • Almacenamiento seguro: Nunca almacenes contraseñas en texto plano. Usa funciones de hash como SHA-256 para almacenar solo el hash de la contraseña.
  • Protección contra ataques de fuerza bruta: Limita el número de intentos fallidos para evitar ataques de fuerza bruta.

Autentificación basada en tokens (JWT)

Los tokens JWT (JSON Web Tokens) son una forma segura de autentificar usuarios o dispositivos. Un JWT es un token codificado que contiene información sobre la identidad y permisos del usuario.

Para usar JWT en el ESP32, necesitamos una biblioteca como ArduinoJson para manejar el formato JSON y una función para verificar la firma del token.

#include <WiFi.h>
#include <ArduinoJson.h>
#include <base64.h>

const char* ssid = "TuRedWiFi";
const char* password = "TuContraseñaWiFi";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Conectando a WiFi...");
  }
  Serial.println("Conectado a WiFi");
}

bool verificarJWT(String token) {
  // Decodificar el token JWT
  int punto1 = token.indexOf('.');
  int punto2 = token.indexOf('.', punto1 + 1);

  String header = token.substring(0, punto1);
  String payload = token.substring(punto1 + 1, punto2);
  String firma = token.substring(punto2 + 1);

  // Verificar la firma (simplificado)
  // En un caso real, usarías una biblioteca de criptografía para verificar la firma.
  return true; // Simulación de verificación exitosa
}

void loop() {
  if (Serial.available()) {
    String token = Serial.readString(); // Leer el token JWT
    token.trim(); // Eliminar espacios en blanco

    if (verificarJWT(token)) {
      Serial.println("Autentificación exitosa con JWT");
    } else {
      Serial.println("Autentificación fallida con JWT");
    }
  }
}

Autentificación de dispositivos mediante certificados

La autentificación mediante certificados es un método más seguro que utiliza certificados digitales para verificar la identidad de un dispositivo. Este método es común en aplicaciones IoT donde la seguridad es crítica.

El ESP32 soporta TLS/SSL, lo que permite usar certificados para autentificar dispositivos en conexiones seguras.

#include <WiFi.h>
#include <WiFiClientSecure.h>

const char* ssid = "TuRedWiFi";
const char* password = "TuContraseñaWiFi";

const char* server = "tuservidor.com";
const char* certificado = "-----BEGIN CERTIFICATE-----\n"
                          "TU_CERTIFICADO_AQUI\n"
                          "-----END CERTIFICATE-----\n";

WiFiClientSecure client;

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Conectando a WiFi...");
  }
  Serial.println("Conectado a WiFi");

  client.setCACert(certificado); // Configurar el certificado
}

void loop() {
  if (!client.connected()) {
    if (client.connect(server, 443)) {
      Serial.println("Conexión segura establecida");
      client.println("GET / HTTP/1.1");
      client.println("Host: " + String(server));
      client.println("Connection: close");
      client.println();
    } else {
      Serial.println("Error al conectar");
    }
  }

  while (client.available()) {
    String line = client.readStringUntil('\n');
    Serial.println(line);
  }
}

Autentificación de mensajes

La autentificación de mensajes asegura que los mensajes recibidos provienen de una fuente confiable y no han sido alterados. Esto se logra mediante firmas digitales o códigos de autentificación de mensajes (MAC).

Podemos usar algoritmos como HMAC-SHA256 para autentificar mensajes.

#include <WiFi.h>
#include <mbedtls/md.h>

const char* ssid = "TuRedWiFi";
const char* password = "TuContraseñaWiFi";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Conectando a WiFi...");
  }
  Serial.println("Conectado a WiFi");
}

String calcularHMAC(String mensaje, String clave) {
  byte hmacResult[32];
  mbedtls_md_context_t ctx;
  mbedtls_md_init(&ctx);
  mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1);
  mbedtls_md_hmac_starts(&ctx, (const unsigned char*)clave.c_str(), clave.length());
  mbedtls_md_hmac_update(&ctx, (const unsigned char*)mensaje.c_str(), mensaje.length());
  mbedtls_md_hmac_finish(&ctx, hmacResult);
  mbedtls_md_free(&ctx);

  String resultado;
  for (int i = 0; i < 32; i++) {
    char str[3];
    sprintf(str, "%02x", (int)hmacResult[i]);
    resultado += str;
  }
  return resultado;
}

void loop() {
  if (Serial.available()) {
    String mensaje = Serial.readString(); // Leer el mensaje
    mensaje.trim(); // Eliminar espacios en blanco

    String clave = "claveSecreta";
    String hmac = calcularHMAC(mensaje, clave);

    Serial.println("HMAC calculado: " + hmac);
  }
}