Un sistema de licencia seguro

8

Por lo tanto, estoy tratando de pensar en una buena manera de verificar si la clave de licencia que un usuario proporciona para un programa es legítima o no.

Supongamos que esta es la forma en que obtienen la licencia

  1. Ellos hacen algún tipo de compra.
  2. Un servidor genera una licencia basada en su nombre de usuario
  3. El servidor da licencia al usuario
  4. Cuando el usuario intenta usar el programa por primera vez, usa dicha clave de licencia
  5. El servidor comprueba si la licencia es legítima.

La parte de la que tengo una pregunta es cuál es una buena manera de generar una licencia "segura" con solo un nombre de usuario.

Actualmente tengo algo similar a esto en un servidor Java.

username += "a long random string literal here";
        username = username.toUpperCase();
        md = MessageDigest.getInstance("SHA-256");
           md.update(username.getBytes());
            byte[] mdbytes = md.digest();

Como puede ver, estoy agregando una cadena larga y aleatoria al nombre de usuario, y luego lo hago sin distinción de mayúsculas y minúsculas al cambiarlo a mayúsculas.

Estoy usando SHA en el nombre de usuario editado.

Entonces, ¿cuáles son exactamente los puntos débiles en esto? ¿Es su mejor manera de comprobar las licencias?

Obviamente, el cliente nunca vería el método de generación, así que no veo cómo podrían generar sus propias licencias a menos que obtengan la cadena que estoy agregando al nombre de usuario.

    
pregunta Austin 24.10.2012 - 10:55
fuente

3 respuestas

20
El método de

generación de la licencia no es realmente tan importante, siempre que no sea trivial. El truco es cómo su cliente verifica que la licencia sea correcta.

Digamos que haces algo como esto:

BOOL verifyLicense (char* licenseKey)
{
    BOOL result = false;

    if(strlen(licenseKey) > 128)
        return false;

    char* url = (char*)malloc(1024);
    sprintf(url, "%s%s", LicenseServerBaseURL, licenseKey);

    char* response = http_get(url);

    if (strcmp(response, "OK") == 0)
        result = true;

    free(result);
    free(url);
}

Esto es bastante simple: hacemos algunas verificaciones básicas de la clave de licencia, creamos una URL que contiene la clave de licencia, luego hacemos un GET HTTP al servidor para verificar la licencia. Si devuelve "OK" lo aceptamos.

El problema con esto es que cualquiera puede desarmar al cliente:

 ...
 push 06f2011c        ; address of url string
 call http_get        ; http_get(url)
 mov ebx, eax         ; store a copy of the result address
 push 04830040        ; ASCII "OK"
 push eax             ; address of response string
 call msvcrt.strcmp   ; strcmp(response, "OK")
 test eax, eax        ; if( ^ == 0 )
 jnz exit             ; skip if branch if non-zero
 mov eax, 1           ; result = true
exit:
 push ebx
 call msvcrt.free     ; free(result)
 push 06f2011c
 call msvcrt.free     ; free(url)
 ret

Todo lo que tengo que hacer es alterar el jnz exit a una serie de instrucciones nop , por lo que el salto nunca se toma y el resultado siempre es verdadero. De esta forma, se acepta cualquier clave de licencia. Aún mejor, simplemente podría modificar el inicio del método para establecer inmediatamente eax en 1 y devolver, por lo que nunca es molesto pedirle a su servidor la validación de la licencia.

Entonces, ¿cómo resolvemos este problema? Desafortunadamente para ti, no podemos. Se está encontrando con el problema de DRM, que esencialmente establece que si le entrega a alguien información, siempre puede cambiarla. No importa cuánto ofusque su código, es posible que el usuario eventualmente realice una ingeniería inversa y descubra cómo realizar cambios o extraer datos. Si encripta el contenido, finalmente tendrá que tener la clave en el sistema para descifrarlo, por lo que siempre hay una forma para que el usuario extraiga esa clave y descifre el contenido de forma permanente.

Lo mejor que puedes hacer es hacerlo difícil, lo que implica mucho tiempo y esfuerzo. Eventualmente, su software será resquebrajado y terminará en un sitio de torrent en algún lugar. Apesta a los desarrolladores que usan este tipo de modelo de negocio, pero es el mundo en el que vivimos. Mi sugerencia es que se vaya por una de dos rutas:

  1. Cree un sistema de licencias básico que funcione y acepte el hecho de que algunas personas lo piratearán. Preste servicio a sus clientes reales al dedicar su tiempo de desarrollo a realizar mejoras en el software, en lugar de implementar y mantener sistemas DRM draconianos.

  2. Modifique todo su paradigma de desarrollo y negocio, de modo que su producto sea un servicio en lugar de una aplicación de software. SaaS ha sido muy exitoso, ya que es (prácticamente) imposible piratear servicios, y el modelo le permite realizar en tiempo real realice cambios en su base de código y realice análisis en el uso.

Si elige la opción 1, no implique un servidor para la validación. Agrega complejidad, no proporciona seguridad adicional, trae algunas preocupaciones de privacidad y hace que sea imposible para los usuarios usar su software si su servidor de licencias no funciona. Solo quédate con algo simple, por ej. un hash del nombre de usuario y un valor secreto en el lado del cliente. Es trivial romperlo, pero le da una barrera mínima a la piratería.

    
respondido por el Polynomial 24.10.2012 - 11:25
fuente
1

Si todo lo que intentas hacer es generar una clave de licencia que sea difícil de replicar, al usar el nombre de usuario como parte de la entrada al hash, harás que la clave de licencia sea más débil y, por lo tanto, más fácil de adivinar. El nombre de usuario no es aleatorio y, por lo tanto, disminuye la entropía de la clave de licencia resultante, y el atacante puede adivinar el nombre de usuario, quien podría, haciendo algunas suposiciones acerca de su método, forzar la fuerza bruta de su clave mucho más fácilmente.

Si está agregando una cadena aleatoria al nombre de usuario, no hay ninguna buena razón para usar el nombre de usuario, solo use todos los datos aleatorios. La única razón por la que usarías el nombre de usuario para generar la clave de licencia sería hacerlo reversible.

    
respondido por el GdD 24.10.2012 - 11:07
fuente
-1

O podría enviar al usuario un correo electrónico con un enlace de verificación. Una vez que hacen clic en el enlace, su servidor sabe que el software es legítimo. la aplicación periódicamente 'llama a casa' para ver si se ha verificado, y se limita a las funciones si recibe una respuesta negativa.

Esto también puede proteger contra el exceso de activaciones múltiples, ya que el servidor sabría cuántas licencias tiene un usuario y cuántas se han utilizado. Obviamente, toda la comunicación entre la aplicación y el servidor se realiza a través de ssl.

    
respondido por el David J Dunmore 24.10.2012 - 12:27
fuente

Lea otras preguntas en las etiquetas