>_ DevTrendses

Idioma

Inicio

Lenguajes

Secciones

Frontend Backend Móvil DevOps AI / ML GameDev Blockchain Embebidos Seguridad
Python

Cómo enmascarar automáticamente datos de pasaporte y números de tarjeta en logs

Hace poco estábamos investigando un incidente en producción donde un servicio caído volcó un JSON completo con el cuerpo de la solicitud del usuario en ELK. Contenía un número de tarjeta de crédito, dirección de domicilio y número de teléfono. Registrar todo con fines de depuración es una práctica común, pero cuando estos volcados terminan en almacenamiento, los equipos de seguridad plantean preguntas muy incómodas. Escribir patrones regex para cada cosa se vuelve tedioso rápido. Se rompen en formatos complejos, omiten nombres y confunden secuencias aleatorias de números con identificadores reales.

Hay diferentes formas de resolver este problema. Una de las herramientas de código abierto más maduras disponibles es Presidio, desarrollada por la comunidad bajo la organización data-privacy-stack.

¿Qué hay bajo el capó y por qué lo necesitas

Presidio ayuda a encontrar y enmascarar información de identificación personal (PII) en textos, hojas de cálculo e incluso imágenes. El proyecto fue originalmente creado por ingenieros de Microsoft como una biblioteca de código abierto, y desde entonces se ha mudado a una organización separada, acumulando más de 10,000 estrellas en GitHub.

La idea central aquí es simple: dividir la tarea de protección de privacidad en dos pasos independientes — análisis y anonimización.

En lugar de un script monolítico, obtienes dos módulos separados:

  1. presidio-analyzer — examina el texto entrante, encuentra entidades como números de pasaporte, números de teléfono, direcciones de correo electrónico o nombres, y devuelve las coordenadas de los hallazgos junto con una puntuación de confianza.
  2. presidio-anonymizer — toma el marcado del analizador y aplica reglas de transformación: reemplaza con marcadores de posición, cifra, enmascara con asteriscos o simplemente elimina.

Esta separación es conveniente cuando necesitas registrar solo el hecho de la detección de datos sin modificar el texto en sí, o cuando quieres configurar flexiblemente el método de enmascaramiento para diferentes tipos de campos.

Cómo funciona la detección de entidades

Si has intentado analizar texto solo con expresiones regulares, conoces su principal desventaja: regex no entiende el contexto. Encontrará una secuencia de 16 dígitos, pero no sabrá si es un número de tarjeta o un SKU de producto en un almacén.

Presidio combina múltiples enfoques a la vez:

  • Expresiones regulares y sumas de verificación (por ejemplo, el algoritmo de Luhn para números de tarjetas bancarias o validadores de IBAN).
  • Modelos NLP preentrenados basados en spaCy o Hugging Face Transformers para reconocimiento de entidades nombradas (NER) — personas, ubicaciones, organizaciones.
  • Análisis contextual de palabras. Si una secuencia de números está precedida por palabras como "teléfono", "tel" o "llamar", la puntuación de confianza del detector aumenta.
  • Diccionarios y listas de palabras vacías.

Ejemplo en Python

Veamos cómo se ve una tubería básica en Python. Primero, instala los paquetes:

pip install presidio-analyzer presidio-anonymizer
python -m spacy download en_core_web_lg

Primero, ejecuta el analizador para encontrar puntos vulnerables en la cadena:

from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine

text = "Привет, меня зовут John Doe. Мой рабочий email john.doe@example.com, а телефон +1-555-0199."

analyzer = AnalyzerEngine()
results = analyzer.analyze(text=text, entities=["EMAIL_ADDRESS", "PHONE_NUMBER", "PERSON"], language='en')

print("Найденные сущности:")
for res in results:
    print(f"Тип: {res.entity_type}, позиция: {res.start}:{res.end}, уверенность: {res.score:.2f}")

Después de que el analizador devuelve los desplazamientos y tipos de entidad, conecta el módulo de anonimización:

anonymizer = AnonymizerEngine()
anonymized_result = anonymizer.anonymize(
    text=text,
    analyzer_results=results
)

print("\nРезультат обработки:")
print(anonymized_result.text)

La salida es una cadena donde los nombres se reemplazan con <PERSON> y los contactos se reemplazan con <EMAIL_ADDRESS> y <PHONE_NUMBER>. Si lo deseas, puedes configurar el hash, el enmascaramiento parcial de caracteres o el reemplazo con datos falsos a través de Faker.

Agregando reglas personalizadas

Desde el primer momento, el proyecto está bien ajustado para formatos internacionales: números de seguro social de EE.UU., tarjetas Visa y Mastercard, números de teléfono internacionales, correo electrónico. Para datos locales como pasaportes rusos, INN o SNILS, necesitarás escribir tus propios reconocedores.

Es bastante simple hacerlo usando clases integradas:

from presidio_analyzer import Pattern, PatternRecognizer

# Паттерн для поиска СНИЛС (формат XXX-XXX-XXX YY)
snils_pattern = Pattern(
    name="snils_pattern",
    regex=r"\b\d{3}-\d{3}-\d{3}\s\d{2}\b",
    score=0.85
)

snils_recognizer = PatternRecognizer(
    supported_entity="RU_SNILS",
    patterns=[snils_pattern],
    context=["снилс", "страховой", "пенсионный"]
)

analyzer.registry.add_recognizer(snils_recognizer)

Cuando el analizador ve una coincidencia contra la expresión regular y encuentra palabras de la lista context cerca, eleva la puntuación de confianza al máximo.

Otras características de la biblioteca

Además de trabajar con texto plano, el repositorio contiene módulos auxiliares para tareas relacionadas:

  • presidio-image-redactor — encuentra texto en imágenes y escaneos de PDF a través de OCR (Tesseract) y pinta sobre los datos personales detectados con cajas negras directamente en los píxeles. Útil para procesar escaneos de pasaporte antes de enviar a servicios externos.
  • Integración con pipelines de LLM. Presidio se usa frecuentemente como middleware antes de enviar prompts a OpenAI o Anthropic: eliminas los datos personales del usuario de la solicitud, envías el texto anonimizado al modelo, y de vuelta, restauras los datos a su lugar si es necesario.
  • API REST en FastAPI, empaquetada en contenedores Docker. No tienes que escribir todo el servicio en Python — puedes desplegar el analizador como un microservicio y llamarlo desde backends en Go, Java o Node.js.

Posibles desafíos

La primera sutileza es el hambre de recursos. Si conectas transformadores pesados como RoBERTa o BERT para un reconocimiento de entidades más preciso, la inferencia requerirá memoria y ralentizará el procesamiento del flujo de datos. Ejecutar un pipeline NLP completo de forma síncrona en cientos de miles de RPS será pesado — necesitarás descargar el enmascaramiento a trabajadores asíncronos de Kafka o Celery.

El segundo punto son los modelos de idioma ruso. El en_core_web_lg básico de spaCy maneja bien el inglés, pero para ruso necesitarás conectar el modelo ru_core_news_lg o ajustar tu propio reconocedor NER para las specifics de tu texto.

Aplicaciones prácticas

Presidio es útil cuando una empresa necesita cumplir con la Ley Federal 152, GDPR o HIPAA, pero reescribir la infraestructura existente desde cero es demasiado costoso.

La biblioteca se adapta bien a tres escenarios:

  • Limpiar logs y trazas antes de enviar a sistemas de monitoreo (Sentry, OpenTelemetry, ELK).
  • Preparar conjuntos de datos para entrenamiento de modelos de ML o análisis sobre datos reales de usuarios.
  • Filtrar mensajes entrantes y salientes en chatbots y sistemas RAG basados en modelos de lenguaje grandes.

Si buscas un kit de herramientas listo para usar para el enmascaramiento de datos sin tener que escribir analizadores desde cero, el repositorio definitivamente vale la pena marcar y probar localmente con tus propios ejemplos.

Proyectos relacionados