Reconocimiento facial con Node.js: arquitectura, implementación y seguridad

Crear una aplicación web de reconocimiento facial desde cero es más que un desafío de programación: es un proceso de aprendizaje, resolución de problemas y puesta en común de conocimientos.

En el panorama digital actual, la verificación de identidad es primordial para las aplicaciones Node.js en diversas industrias. La verificación de identidad implica varios pasos, incluyendo la validación de documentos, los controles biométricos y las búsquedas en bases de datos.

La precisión de la verificación de identidad es crucial. Una implementación completa debe combinar una arquitectura clara, modelos adecuados, controles de seguridad, pruebas automatizadas, supervisión y mecanismos de detección de vitalidad.

Planificación de la aplicación de reconocimiento facial

Antes de escribir código, conviene definir las funciones principales, investigar las bibliotecas disponibles y diseñar la arquitectura general del sistema.

  • Definí las funciones principales: registro facial, reconocimiento, seguridad y rendimiento.
  • Investigué las bibliotecas: elegí face-api.js por su precisión y compatibilidad con Node.js.
  • Dibujé la arquitectura: describí la interacción entre el frontend, el backend, el modelo de IA, la base de datos y la caché.

Una buena planificación y una investigación previa ahorran tiempo y ayudan a evitar problemas importantes más adelante.

Configuración inicial del proyecto Node.js

El proyecto se inicializó con npm init y una estructura modular de carpetas como src/, models/ y public/.

El control de versiones comenzó con Git y GitHub, utilizando un archivo .gitignore profesional y mensajes de commit claros.

También se configuraron ESLint, Prettier y Jest para mantener la calidad del código.

Una estructura limpia y la adopción temprana de buenas prácticas facilitan la colaboración y el crecimiento de la aplicación.

Arquitectura del backend con Express.js

Express.js se utilizó como base del backend, incorporando desde el principio middleware de seguridad y utilidades.

const express = require('express');const helmet = require('helmet');const cors = require('cors');const rateLimiter = require('./middleware/rateLimiter');const app = express();app.use(helmet());app.use(cors());app.use(rateLimiter);app.use(express.json());

Helmet añade encabezados de seguridad, CORS permite controlar las solicitudes entre distintos orígenes y el limitador de velocidad ayuda a proteger la aplicación frente a ataques de fuerza bruta.

Capas recomendadas del servidor

  • Rutas: definen los puntos de entrada de la API.
  • Controladores: reciben las solicitudes y generan las respuestas.
  • Capa de servicios: contiene la lógica de extracción y comparación de rostros.
  • Base de datos: almacena los identificadores y las representaciones faciales.
  • Middleware: controla la seguridad, las cargas de archivos, la limitación de solicitudes y los errores.

Registro de rostros

Para registrar un rostro, se creó un endpoint que acepta un nombre y una imagen, extrae la representación facial y la almacena en la base de datos.

// src/controllers/faceController.jsconst enrollFace = async (req, res) => { const { name } = req.body; const image = req.file.path; // Detect face and extract embedding const embedding = await faceService.extractEmbedding(image); // Save to database const faceId = await db.saveFace({ name, embedding }); res.json({ success: true, id: faceId });};

El uso de una capa de servicios mantiene limpio el controlador y facilita las pruebas.

El almacenamiento de embeddings en SQLite permite realizar búsquedas rápidas y administrar los datos con sencillez.

Embeddings faciales

Un embedding facial es una representación numérica de las características de un rostro. El proceso de registro convierte la imagen en un vector que posteriormente puede compararse con otros vectores almacenados.

La aplicación debe comprobar que la imagen contiene un rostro válido antes de guardar el embedding. También es recomendable controlar los casos en los que aparecen varios rostros o la imagen no tiene suficiente calidad.

Lógica de reconocimiento facial

El endpoint de reconocimiento compara el embedding de la imagen cargada con todos los embeddings almacenados y devuelve la coincidencia más cercana.

// src/services/faceRecognitionService.jsconst recognizeFace = async (imagePath) => { const queryEmbedding = await extractEmbedding(imagePath); const faces = await db.getAllFaces(); let bestMatch = null; let bestDistance = Infinity; for (const face of faces) { const distance = euclideanDistance(queryEmbedding, face.embedding); if (distance < bestDistance) { bestDistance = distance; bestMatch = face; } } return { match: bestMatch, confidence: 1 - bestDistance };};

La distancia euclídea es una forma sencilla y eficaz de medir la similitud entre dos embeddings faciales.

Para casos de uso más avanzados, se puede experimentar con la similitud del coseno o incluso entrenar un clasificador personalizado.

Interpretación de la distancia y la confianza

El algoritmo selecciona el rostro cuya distancia respecto al embedding consultado sea menor. Sin embargo, la aplicación debe establecer un umbral de aceptación antes de considerar que existe una coincidencia válida.

El valor de confianza mostrado en el ejemplo se calcula como 1 - bestDistance. Este valor debe interpretarse de acuerdo con el modelo utilizado y calibrarse mediante pruebas con imágenes reales, porque una distancia menor no equivale automáticamente a una identidad confirmada.

Las pruebas deben incluir imágenes con distintas condiciones de iluminación, ángulos, expresiones, resoluciones y oclusiones parciales.

Validación y seguridad de las imágenes

Para proteger las cargas de archivos, se implementó un middleware que comprueba el tipo y el tamaño de cada archivo.

// src/middleware/upload.jsconst multer = require('multer');const upload = multer({ dest: 'uploads/', limits: { fileSize: 10 * 1024 * 1024 }, fileFilter: (req, file, cb) => { if (!file.mimetype.startsWith('image/')) { return cb(new Error('Only image files are allowed!'), false); } cb(null, true); },});module.exports = upload;

Validar siempre el tipo y el tamaño de los archivos ayuda a prevenir abusos y vulnerabilidades de seguridad.

  • Rechazar archivos que no sean imágenes.
  • Limitar el tamaño máximo de la carga.
  • Evitar confiar únicamente en la extensión del archivo.
  • Eliminar los archivos temporales cuando ya no sean necesarios.
  • Proteger los endpoints con autenticación y autorización.

Frontend para registrar y reconocer rostros

Se utilizó EJS para representar páginas dinámicas destinadas al registro y al reconocimiento facial. Esto permite renderizar contenido en el servidor e integrarlo fácilmente con el backend.

<!-- src/views/enroll.ejs --><form id="enrollForm" enctype="multipart/form-data" method="POST" action="/api/face/enroll"> <input type="text" name="name" placeholder="Enter name" required /> <input type="file" name="image" accept="image/*" required /> <button type="submit">Enroll Face</button></form>

Para mejorar la experiencia de usuario, se añadió una zona de arrastrar y soltar junto con la posibilidad de seleccionar un archivo mediante un clic.

// public/enroll.jsconst dropArea = document.getElementById('drop-area');dropArea.addEventListener('dragover', (e) => { e.preventDefault(); dropArea.classList.add('highlight');});dropArea.addEventListener('drop', (e) => { e.preventDefault(); document.getElementById('imageInput').files = e.dataTransfer.files;});

Una interfaz limpia e intuitiva es tan importante como una lógica backend sólida, especialmente en aplicaciones basadas en IA.

Cliente FaceClient y Azure AI Face

El servicio Face de Azure AI ofrece algoritmos de IA que detectan, reconocen y analizan caras humanas en las imágenes.

FaceClient es la interfaz principal para los desarrolladores que interactúan con el servicio Azure AI Face.

Azure AI Face admite el acceso multiservicio y de un solo servicio. Cree una cuenta de varios servicios de Azure AI si planea acceder a varios servicios de Azure AI en un único punto de conexión o clave.

La cuenta de Azure debe tener asignado un rol Cognitive Services Contributor a fin de que pueda aceptar los términos de IA responsable y crear un recurso.

Credenciales y autenticación

Tanto la credencial de clave como la credencial de id. Se recomienda encarecidamente usar las credenciales de Id. para mejorar la seguridad.

Se puede usar un punto de conexión regional o un subdominio personalizado para la autenticación.

Un punto de conexión regional es el mismo para cada recurso de una región. Aquí se puede consultar una lista completa de los puntos de conexión regionales admitidos.

Tenga en cuenta que los puntos de conexión regionales no admiten la autenticación de Id. de Entra de Microsoft.

Un subdominio personalizado, por otro lado, es un nombre que es único para el recurso.

Para crear el cliente con una credencial de id., también deberá registrar una nueva aplicación de id.

La autenticación debe configurarse de acuerdo con el tipo de endpoint seleccionado: los endpoints regionales no admiten la autenticación de Identificador de Entra de Microsoft, mientras que un subdominio personalizado identifica de forma única el recurso.

Operaciones de ejecución prolongada

Las operaciones de ejecución prolongada constan de una solicitud inicial enviada al servicio para iniciar una operación, seguida de sondear el servicio a intervalos para determinar si la operación se ha completado o ha producido un error y, si se ha realizado correctamente, para obtener el resultado.

La aplicación debe controlar los estados de ejecución, los errores, los tiempos de espera y los reintentos de forma explícita.

Detección de vitalidad y verificación facial

El objetivo de la detección de vitalidad es garantizar que el sistema interactúe con una persona físicamente presente en el momento de la autenticación.

Para combatir el fraude, la Detección de vitalidad de Didit emplea técnicas pasivas y activas para garantizar que los usuarios estén físicamente presentes durante el proceso de verificación, evitando la suplantación de identidad y los ataques de deepfake.

Antes de cargar la secuencia de vídeo, el servidor de aplicaciones tiene que crear una sesión y, a continuación, el cliente de front-end podría cargar la carga con para session authorization token llamar a la detección de ejecución.

La operación de detección de ejecución no solo puede confirmar si la entrada es activa o suplantación de identidad, sino que también comprueba si la entrada pertenece a la cara de la persona esperada, lo que se denomina detección de ejecución con verificación facial.

Este paquete solo es responsable de que el servidor de aplicaciones cree, consulte, elimine una sesión y obtenga registros de auditoría.

Flujo recomendado de verificación

  1. El servidor crea una sesión de verificación.
  2. El cliente recibe un token de autorización de sesión.
  3. El cliente carga la secuencia de vídeo mediante el token.
  4. El servicio analiza si la entrada corresponde a una persona real o a una suplantación.
  5. La verificación facial comprueba si la entrada pertenece a la persona esperada.
  6. El servidor consulta el resultado y conserva los registros de auditoría necesarios.

Verificación de identidad en Node.js

La implementación de una verificación de identidad integral en Node.js se puede simplificar con la plataforma modular de Didit.

Didit ofrece un conjunto de herramientas diseñadas para mejorar la seguridad y garantizar el cumplimiento de las regulaciones KYC/AML.

Por ejemplo, el producto Verificación de ID de Didit automatiza la autenticación de documentos, verificando identificaciones de más de 190 países con una precisión incomparable.

Esto reduce la revisión manual y acelera la incorporación de usuarios.

La verificación de identidad implica varios pasos, incluyendo la validación de documentos, los controles biométricos y las búsquedas en bases de datos.

La combinación de validación documental, biometría facial y detección de vitalidad permite crear un proceso de incorporación más completo que el reconocimiento facial aislado.

Supervisión de la API y comprobaciones de salud

Un endpoint de comprobación de estado sencillo es fundamental para la supervisión y la automatización.

// src/routes/faceRoutes.jsrouter.get('/health', (req, res) => { res.json({ status: 'ok', uptime: process.uptime() });});

También se creó un endpoint de estado más detallado para supervisar la API.

// src/routes/faceRoutes.jsrouter.get('/api/status', async (req, res) => { res.json({ status: 'ok', version: process.env.npm_package_version, environment: process.env.NODE_ENV, uptime: process.uptime(), redis: redisClient.status, });});

Los endpoints de salud y estado facilitan el seguimiento del tiempo de actividad y el diagnóstico de problemas.

Registro de eventos y diagnóstico

Un registro sólido ayuda a depurar y supervisar la aplicación en producción.

// src/config/logger.jsconst { createLogger, transports, format} = require('winston');const logger = createLogger({ level: 'info', format: format.combine( format.timestamp(), format.printf(({ timestamp, level, message }) => `${timestamp} [${level}]: ${message}` ) ), transports: [ new transports.Console() ],});module.exports = logger;

Winston y Morgan pueden integrarse para registrar solicitudes, errores y eventos del sistema.

La habilitación del registro puede ayudar a descubrir información útil sobre los errores.

Para ver un registro de solicitudes y respuestas HTTP, establezca la variable de entorno AZURE_LOG_LEVEL en info.

Pruebas y garantía de calidad

Se escribieron pruebas unitarias y de integración utilizando Jest y Supertest para comprobar la fiabilidad de la API.

Las pruebas manuales utilizaron imágenes de muestra y casos límite para comprobar todo el flujo, desde el registro hasta el reconocimiento.

También se configuró GitHub Actions para ejecutar pruebas automáticamente en cada push.

// tests/app.test.jsconst request = require('supertest');const app = require('../src/server');describe('API Status', () => { it('should return API status', async () => { const res = await request(app).get('/api/status'); expect(res.statusCode).toEqual(200); expect(res.body).toHaveProperty('status', 'ok'); });});

Casos que deben probarse

  • Imagen sin rostro.
  • Imagen con varios rostros.
  • Archivo que no es una imagen.
  • Archivo que supera el límite de tamaño.
  • Rostro registrado con distintas condiciones de iluminación.
  • Rostro desconocido.
  • Solicitudes no autorizadas.
  • Errores del servicio externo.
  • Operaciones de ejecución prolongada que terminan correctamente.
  • Operaciones de ejecución prolongada que producen un error o superan el tiempo de espera.

Contenedorización con Docker

Dockerfile multi-stage

Se utilizó un Dockerfile multi-stage para optimizar el tamaño de la compilación y mejorar la seguridad.

# DockerfileFROM node:18-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm installCOPY . .RUN npm run buildFROM node:18-alpineWORKDIR /appCOPY --from=builder /app .EXPOSE 3000USER nodeCMD ["npm", "start"]

Garantizar que todas las dependencias nativas, especialmente las de TensorFlow.js, funcionaran correctamente en Docker requirió pruebas y ajustes.

Docker Compose para desarrollo local

Docker Compose facilita la ejecución conjunta de la aplicación, Redis y otros servicios.

# docker-compose.dev.ymlversion: '3'services: app: build: . ports: - "3000:3000" volumes: - .:/app - /app/node_modules environment: - NODE_ENV=development - REDIS_HOST=redis redis: image: redis:alpine ports: - "6379:6379"

Despliegue en producción

Para producción, se utilizó un archivo docker-compose.prod.yml separado y se configuraron variables de entorno para la seguridad y el rendimiento.

npm run docker:prod

La aplicación se desplegó en Render o en plataformas similares para ofrecer acceso público.

La mayoría de las plataformas cloud son compatibles con Docker, lo que simplifica el despliegue.

Documentación y mantenimiento

La documentación debe incluir instrucciones detalladas de instalación, documentación de la API y capturas de pantalla.

Un proyecto de reconocimiento facial debe documentar la configuración de credenciales, los endpoints disponibles, los formatos de las cargas, los límites de tamaño, las respuestas de error y las variables de entorno.

Este proyecto agradece las contribuciones y sugerencias.

Cuando se envía una solicitud de incorporación de cambios, un bot de CLA determinará de forma automática si tiene que aportar un CLA y completar la PR adecuadamente, por ejemplo, la etiqueta y el comentario.

Solo siga las instrucciones que le dará el bot.

Este proyecto ha adoptado el Código de conducta de Microsoft Open Source.

Arquitectura aplicación reconocimiento facial Node.js

Revoluciona tu piel con el Diagnóstico Facial 3D más avanzado

tags: #reconocimiento #facial #node #js