entre Desarrolladores

Recibe ayuda de expertos

Registrate y pregunta

Es gratis y fácil

Recibe respuestas

Respuestas, votos y comentarios

Vota y selecciona respuestas

Recibe puntos, vota y da la solución

Pregunta

2votos

Sistema para evitar copias de software sin licencia

Buenas pretendo añadir a un software Java un sistema para verificar que el usuario que lo utiliza tiene licencia para hacerlo(para controlar el pago de las cuotas), en este sentido soy bastante realista y sé que no hay nada seguro al cien por cien, dicho esto me gustaría saber cual es el método mas seguro de hacerlo.
De momento mi planteamiento es crear un servidor de autenticación de licencias en un cualquier hosting, la idea es incluir en cada copia del software dentro de algún proceso critico del mismo( por ejemplo al arrancar el programa y al iniciar una sesión de usuario) una llamada a dicho servidor con una clave, tipo las API KEY de las redes sociales, y que este servidor devuelva una respuesta que acepte o bloquee el programa, creo que es la mejor manera de hacerlo.

Respecto a esta idea aún sin haberle dado muchas vueltas me surgen varias dudas:
1.- No se si será necesario utilizar, además de SSL, algún sistema criptográfico de cifrado en el proceso,lo digo para evitar que el servidor de autenticación devuelva un simple true o false ya que sería bastante facil de burlar el sistema, conozco algunos sistemas de cifrado pero la verdad no se en que caso se debe utilizar cada uno, y en este caso concreto no se cual será mejor utilizar.

2.- Respecto a los String donde se almacena la API KEY que utilice la copia del programa, así como la URL donde este servidor de autenticación me preocupa la facilidad de localizar un string cuando se hace una descompilación del programa, ya que estos se pueden leer tal cual, tan solo habría que monitorizar el tráfico cuando se inicia el programa, localizar la llamada al servidor de autenticación y buscar dicha URL en el código descompilado para saber en que parte se realiza el proceso de validación, con lo que una vez localizado el trozo de código conseguir burlarlo puede ser un proceso bastante sencillo, se me ocurre a modo casero guardar el String como distintos caracteres en distintas variables para que no sea guardado en tiempo de compilación al completo, y utilizar un sistema que monte dicho String en tiempo de ejecución, de este modo solo estaría almacenado en la memoria RAM lo que dificulta mas su localización, pero no estaría visible en el código descompilado, eso es lo primero que se me ha ocurrido no se como se hace esto habitualmente en la práctica.

Puede que parezca complicarlo demasiado y probablemente nadie intentará crackear el programa, pero el sistema tengo que hacerlo igualmente para controlar las cuotas y ya que lo hago prefiero hacerlo bien.

Además de esto utilizaré algún programa para la ofuscación del código, no se que cosas se me han podido escapar, así que estoy abierto a cualquier idea o consejo.

3 Respuestas

1voto

Gilberto Puntos1210

Primero que nada, es muy importante que sepas, que tengas muy presente, que ese esquema de autenticación no es infalible, es bastante burlable de hecho, más en Java.
Piensa en el esquema de manera abstracta, no te preocupes ahora por la implementación. Necesitas por un lado un generador de claves, el cual tendrás guardado en un bunker para generar las claves a quienes te paguen. Por otro lado, tendrás un validador de claves, incluido en cada copia de tu software.
La idea es que cualquiera puede bajar tu software, comprarlo pirata en el metro, copiarlo de un amigo, etc; pero necesitan una clave válida para activarlo.
Opción 1: Si esto funciona offline, entonces la validación consiste únicamente en hacer checksums y cosas así, pero no tienes manera de saber si alguien usa y reusa la misma clave N veces.
Opción 2: Si esto funciona online, entonces la validación consiste en que el software se conecta a un servidor que tú pusiste, envía la clave y el servidor contesta si la clave es válida y si es nueva (aquí ya puedes detectar si es repetida y rechazarla).
La opción 1 se usaba mucho en los 80's y la bronca es que la gente se pasaba la copia del software junto con la clave que había que teclear para activarlo. Aparte de eso, había quienes se ponían a hacer generadores de claves y entonces aunque no tuvieras una clave válida, conseguías el generador de claves y te hacía una inventada al vuelo que pasaba las validaciones del software.
La opción 2 es la que se usa hoy en muchos programas, la bronca es que sólo se puede activar el software cuando se tiene conexión a internet (cada vez es menos problema, pero en algunos casos no deja de ser un impedimento). La bronca principal de esta opción es que se puede hacer un servidor falso de autenticación que conteste que cualquier clave es válida. Para dificultar esto pues hay que hacer un protocolo muy complicado para que sea difícil de implementar el servidor falso, pero solamente se tiene que implementar una vez y luego se pone en internet y todo mundo tiene acceso al servidor falso.
Y la bronca que tienen ambos, principalmente en Java, es que al final sabes que existe un código similar a esto dentro del software:

if (Validador.aplicacionEsLegitima()) {
  ejecutarNormalmente();
} else {
  decirleAlUsuarioQueEsPiratota();
  enviarUnMailATodosSusContactosAcusandoloDePiratota();
  System.exit(-1);
}
Por lo tanto, lo único que hay que hacer para burlar el software, es encontrar la clase Validador, y sustituirla por una clase que tenga esto:
public class Validador {
  public static boolean aplicacionEsLegitima() {
    return true;
  }
}

Y con eso ya el software no pedirá clave alguna.
Para burlar eso, puedes hacer varias cosas: ofuscar el código, o no ponerle "Validador" a tu clase sino "com.mipaquete.Utils" o simplemente meter el método aplicacionEsLegitima() en alguna clase donde no viene al caso para que a nadie se le ocurra buscar ahí o que la llamada no se vea sospechosa (y evidentemente no se llama aplicacionEsLegitima(), ni siquiera checkForUpdates() sino algo tipo cargarPreferencias() o algo que sea de esperarse ver que se llame cuando carga la app).
Pero a fin de cuentas, alguien con suficiente motivación y/o tiempo libre y/o algo que demostrar, se pondrá a descompilar tu aplicación para revisar el código y eventualmente encontrará el punto en donde se conecta la app a tu servidor de autenticación o donde pide la clave, etc.

0voto

Javi2EE comentado

Hola Gilberto perdona por tardar en responder he estado bastante liado, la opción 2 es la que he utilizado, para todo el tema de los nombre he utilizado ProGuard que ofusca el código y lo deja bastante ilegible y para las comunicaciones AES. En la respuesta añado mas detalles te agradezco la ayuda, un saludo

2votos

cobasESP Puntos19650

Yo lo que haría seria hacer que la aplicación, detectase si hay licencia, si no hay capar algunas características por ejemplo. y haya un botón para validar una licencia, en donde tengas que poner un codigo o serial de licencia válido, y por ejemplo un email. Tu a tus clientes, los tendrás en una base de datos y cuando te paguen creas un serial con algún script automatizado, y guardas su email y el serial, en la aplicacion el cliente pondrá el serial y su email y lo guardará y la aplicación detectara que es un usuario de pago. De este modo nadie puede usar el programa al 100% a no ser que tenga un serial linkado a un email, y solo tu puedes dar esa opcion, ya que la aplicación buscara los seriales en la base de datos, no podrán inventarse nuevos seriales y si dan con uno existente tendrán que saber el email del cliente tambien.

1voto

Javi2EE comentado

Gracias cobasESP perdona por tardar en responder, el sistema que he utilizado es casi como dices, solo que he hardcodeado las licencias en cada copia ya que de momento me es fácil gestionarlo de esta manera, el proceso de validación se dispara en algunos procesos críticos como comentabas. He añadido una respuesta con el funcionamiento completo
Gracias por todo amigo, un saludo

1voto

Javi2EE Puntos6630

Buenas al final he utilizado un sistema con un servidor independiente para validar las licencias de los clientes, uso un sistema de encriptacion AES por clave simétrica para las comunicaciones donde el cliente y el servidor utilizan la misma clave, sin entrar en muchos detalles el funcionamiento del sistema es el siguiente:

CLIENTE
1.-El cliente genera un token con el siguiente formato:
{licencia única}-{random char[] cliente}
2.-Utiliza la clave compartida para generar un token encriptado mediante AES a 128 bits y lo envía al servidor.

SERVIDOR
3.-El servidor recibe el token encriptado y lo desencripta con la clave compartida.
4.-Descompone el token en la licencia y el valor random.
5.-Comprueba que la licencia es valida
6.-Si la licencia es válida genera un token de respuesta que contiene el valor aleatorio recibido del cliente:
{random char[] cliente}-{random string}
, si no lo es genera un token erroneo.
7.-El servidor encripta el token y lo manda al cliente

CLIENTE
8.-El cliente recibe el token lo desencripta y comprueba que contiene el valor random que mandó. Si es correcto se da por validado.

Para todo esto uso byte[] o char[] en lugar de String.

Las ventajas de este sistema es que la petición y la respuesta del cliente son distintas cada vez y la comunicación solo el vulnerable si un tercero conoce la clave simétrica.

Así que resumiendo las formas de vulnerar el sistema es o mediante ingeniería inversa o conociendo la clave simétrica. Lo que para mí es mas que suficiente.

Algunas páginas que me han servido:

char[] vs String
Encriptacion AES Java
Protect Java application

Si alguien está interesado en los detalles de la implementación que comente y la añado o abro un repositorio en GitHub.

Un saludo

Por favor, accede o regístrate para responder a esta pregunta.

Otras Preguntas y Respuestas


...

Bienvenido a entre Desarrolladores, donde puedes realizar preguntas y recibir respuestas de otros miembros de la comunidad.

Conecta