Skip to content
← Todas las publicaciones
· Delta1 Labs LicenciamientoSeguridadGuía

Diseñar una huella de máquina que sea estable pero no frágil

El node-locking vincula una licencia a un dispositivo, lo que significa que necesitas una huella lo bastante única para identificar una máquina y lo bastante estable para sobrevivir a una ampliación de RAM. Aquí tienes cómo construir una a partir de señales de hardware ponderadas, emparejarla con tolerancia, hashearla por privacidad, y manejar los casos de VM y cambio de hardware que hacen tropezar a las implementaciones ingenuas.

El node-locking — vincular una licencia a un dispositivo concreto — es solo tan bueno como la huella sobre la que descansa. Equivócala en una dirección y es demasiado laxa: colisiona entre máquinas, y una clave corre silenciosamente en todas partes. Equivócala en la otra dirección y es demasiado frágil: cambia cuando el usuario añade RAM o cambia una tarjeta de red, y un cliente que paga queda de repente bloqueado de un software que posee legítimamente. Una buena huella de máquina enhebra esa aguja — lo bastante única para identificar un dispositivo, lo bastante estable para sobrevivir a la vida ordinaria de ese dispositivo. Aquí tienes cómo construirla.

La tensión: unicidad vs. estabilidad

Cada señal de hardware que podrías usar para la huella se sitúa en algún punto de un espectro entre estable y única, y las dos tiran en direcciones opuestas:

  • Estable, menos única: el identificador de instalación del SO (un GUID escrito una vez cuando se instala el SO), el nombre de la máquina. Rara vez cambian, pero pueden repetirse entre imágenes clonadas.
  • Única, menos estable: una dirección MAC, un número de serie de disco. Muy distintivas, pero una MAC cambia con un adaptador nuevo o una base de acoplamiento, y los discos se reemplazan.
  • Intermedias: identificadores de placa base/BIOS y detalles de la CPU — bastante únicos, bastante estables, pero ausentes o compartidos en algunas máquinas virtuales.

Ninguna señal única es a la vez perfectamente estable y perfectamente única, que es exactamente por qué hashear un único valor — o peor, concatenar varios en un hash — produce una huella frágil. El arreglo no es elegir la «mejor» señal; es combinar varias y emparejarlas con tolerancia.

Recoge varias señales, cada una ponderada

Reúne un puñado de señales independientes y asigna a cada una un peso que refleje cuánto confías en su estabilidad. Un boceto en C#:

record Signal(string Name, string Value, int Weight);

IEnumerable<Signal> CollectSignals() => new[]
{
    new Signal("os-install-id", ReadMachineGuid(),   40),  // very stable
    new Signal("board-id",      ReadBaseboardId(),   30),  // stable
    new Signal("cpu-id",        ReadCpuSignature(),  20),  // stable-ish
    new Signal("primary-mac",   ReadPrimaryMac(),    10),  // volatile
};

Los pesos importan más que las señales exactas. El GUID de instalación del SO y la placa base cargan la mayor parte de la identidad; la MAC contribuye un poco pero no se le permite decidir el resultado por sí sola. Fundamentalmente, mantienes las señales separadas en lugar de plegarlas en un único hash, porque el emparejamiento tiene que poder ver qué señales cambiaron.

Empareja con tolerancia, no con igualdad

La comprobación ingenua — «¿la huella almacenada es igual a la actual?» — es el bug de fragilidad. En su lugar, compara señal por señal y suma el peso de las señales que aún coinciden. El dispositivo es «el mismo» si el peso coincidente supera un umbral:

int MatchScore(IReadOnlyList<Signal> stored, IReadOnlyList<Signal> current)
{
    int score = 0;
    foreach (var s in stored)
    {
        var c = current.FirstOrDefault(x => x.Name == s.Name);
        if (c is not null && FixedTimeEquals(c.Value, s.Value))
            score += s.Weight;
    }
    return score;   // 0..100
}

bool IsSameDevice(IReadOnlyList<Signal> stored, IReadOnlyList<Signal> current)
    => MatchScore(stored, current) >= 70;   // tolerate up to 30 points of drift

Con los pesos de arriba, una ampliación de RAM no cambia nada en este conjunto; un adaptador de red nuevo tira la primary-mac (10 puntos) pero aún puntúa 90; incluso un cambio de CPU y MAC aún supera 70 mientras el GUID de instalación del SO y la placa coincidan. Mientras tanto una máquina genuinamente distinta no comparte ninguno de los anclajes de alto peso y puntúa muy por debajo del umbral. Un número — el umbral — se convierte en el mando que ajustas entre «demasiado laxo» y «demasiado frágil».

señales (ponderadas), total = 100os-install-id · 40board-id · 30cpu-id · 20mac·10umbral = 70emparejado tras un adaptador de red nuevo:puntuación = 90 → aceptado (MAC caída, anclajes aún coinciden)

Hashea en el dispositivo, envía solo el resultado opaco

El fingerprinting toca identificadores de hardware, así que diséñalo para minimizar lo que sale de la máquina. Calcula las señales localmente, y envía al servidor un hash opaco por señal — nunca los números de serie crudos. El servidor almacena valores que no puede revertir a «este cliente posee esta placa base exacta», lo que te da vinculación de dispositivo sin ensamblar un expediente de hardware identificable.

// Salt with the product/key so the same hardware yields different
// fingerprints across products — no cross-product correlation.
string Hash(string raw, string salt) =>
    Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(salt + ":" + raw)));

Salar por producto (o por licencia) significa que el mismo dispositivo produce una huella no relacionada para cada producto, así que dos proveedores nunca pueden correlacionar «la misma máquina» a partir de sus huellas almacenadas. Envía las señales hasheadas y sus pesos; la lógica de emparejamiento de arriba funciona idéntica sobre hashes. Este es el valor por defecto que preserva la privacidad, y es estrictamente mejor para ti también — simplemente hay menos datos sensibles que guardar.

Los casos que hacen tropezar a las implementaciones ingenuas

Dos realidades rompen las huellas que solo se probaron en el portátil de un desarrollador:

Máquinas virtuales y contenedores. Las imágenes de VM clonadas pueden compartir un GUID de instalación del SO e identificadores de placa, haciendo que muchas máquinas «distintas» parezcan idénticas — o, con aleatorización por clon, haciendo que el mismo servidor lógico parezca nuevo en cada arranque. Para entornos virtualizados o efímeros, el fingerprinting de hardware es a menudo la herramienta equivocada por completo; un modelo flotante o concurrente que cuenta el uso simultáneo encaja mejor. (Consulta licencias flotantes y node-locking y gestión de asientos para cuándo elegir cuál.)

Cambio legítimo de hardware. Con el tiempo una placa base muere, un portátil se reemplaza, un disco se cambia. La tolerancia te compra tiempo, pero una reconstrucción completa cruzará el umbral — y debería, porque eso sí es genuinamente un nuevo dispositivo. La respuesta es una ruta de reactivación elegante: cuando la puntuación cae por debajo del umbral, no falles en silencio; trátalo como una nueva activación contra la asignación de dispositivos de la clave, y deja que el cliente mueva su asiento. El servidor ya rastrea las activaciones por clave para los límites de asientos, así que una huella que se ha desplazado es solo una petición de vincular un nuevo dispositivo, sujeta al mismo presupuesto de asientos — no un bloqueo.

La forma de una buena huella

En conjunto, una huella de máquina robusta es: varias señales independientes, cada una ponderada por cuán estable es; un emparejamiento que suma el peso coincidente contra un umbral ajustable en lugar de exigir igualdad exacta; hasheo por señal en el dispositivo con un salt específico del producto para que solo salgan de la máquina valores opacos; y una ruta de reactivación explícita para el día en que el hardware sí cambie de verdad. Constrúyela así y el node-locking hace su trabajo — una clave, un dispositivo — sin convertir una ampliación de RAM en un ticket de soporte. Constrúyela como un único hash de una dirección MAC, y pasarás más tiempo disculpándote con clientes que pagan que deteniendo a los pocos que comparten claves.

Prueba Nebula.NET

Endurece tu código .NET en minutos — empieza con la edición gratuita.