Proteggere le applicazioni dall’uso non autorizzato in Java

Oggi affrontiamo il problema che sorge dopo aver sviluppato un’applicazione e nel momento in cui questa deve essere distribuita. Il problema è tanto più sentito quando l’applicazione è a pagamento, e magari deve essere venduta a clienti. E’ lecito aspettarsi che il programmatore voglia proteggere il suo lavoro, o almeno cercare di scoraggiare potenziali abusi e malintenzionati. Vediamo in questo articolo quali sono le azioni da intraprendere per proteggere la nostra applicazione, supponendo che questa sia stata sviluppata con il linguaggio Java. […]

Oggi affrontiamo il problema che sorge dopo aver sviluppato un’applicazione e nel momento in cui questa deve essere distribuita. Il problema è tanto più sentito quando l’applicazione è a pagamento, e magari deve essere venduta a clienti. E’ lecito aspettarsi che il programmatore voglia proteggere il suo lavoro, o almeno cercare di scoraggiare potenziali abusi e malintenzionati. Vediamo in questo articolo quali sono le azioni da intraprendere per proteggere la nostra applicazione, supponendo che questa sia stata sviluppata con il linguaggio Java.

Le operazioni da eseguire sono le seguenti:

  1. proteggere il codice in modo tale che non possa essere modificato o letto da persone non autorizzate (software chiuso);
  2. evitare che il software venga distribuito a chiunque;
  3. permettere di usare il software in versione demo/trial, e bloccarne eventualmente il funzionamento dopo n giorni.

In generale oggi esistono svariate tecniche più o meno efficaci per proteggere un’applicazione, e queste possono essere generalizzate in 2 categorie: le protezioni più sicure (siamo sicuri che siano le più sicure?!) che possono essere costose in termini di soldi e di tempo per implementarle, o le protezioni più deboli ma spesso di più semplice utilizzo e a basso costo. Il mio consiglio è di optare per la seconda categoria, perché tanto non esiste una protezione sicura al 100% e qualunque venga adottata presto o tardi finirà probabilmente per essere crackkata. Consiglio di scegliere una tecnica di protezione elevata solamente nel caso in cui l’applicazione sviluppata sia di notevoli dimensioni e laddove la quantità di soldi investiti sia stata ingente.

Analizziamo dettagliatamente i 3 punti precedenti, per studiare le tecniche in grado di proteggere un’applicazione.

1. Bloccare lettura/modifica del codice. Per impedire a qualcuno la lettura e la modifica del codice, e dunque di un file, è possibile agire solamente tramite i permessi all’interno di un sistema operativo. Su Linux ad esempio possiamo agire tramite gli sticky bit, assegnando ai vari utenti/gruppi i permessi che riteniamo più adeguati. Questo però non ci aiuta se l’applicazione è distribuita a persone (ad esempio tramite Internet) delle quali non possiamo gestire i sistemi locali.
A questo punto dobbiamo agire diversamente per rendere difficile la vita a chi vuole leggere il  codice e magari appropriarsi degli algoritmi usati. Dal momento che la nostra applicazione è sviluppata in Java, ciò che dobbiamo proteggere sono le classi prodotte dal processo di compilazione (il codice sorgente può semplicemente essere omesso nel software finale, in quando non è necessario). La soluzione in questo caso è di usare un offuscatore di codice, ossia un particolare software che agisce sulle classi compilate, modificandole in modo tale da renderne ardua la lettura in caso di reverse engineering. Per fare ciò un buon software free e aggiornato è ProGuard 4.8 (ultima versione in questo momento):

http://proguard.sourceforge.net/

e qui c’è una guida ben fatta su come utilizzarlo:

http://dellabate.wordpress.com/2010/11/22/java-bytecode-obfuscator-con-proguard/

Offuscatori di codice alternativi a ProGuard sono reperibili in questa lista:

http://proguard.sourceforge.net/alternatives.html

Nella lista precedente io escluderei i software un po’ datati, mentre consiglio yGuard o JBCO.

2. Bloccare la distribuzione non autorizzata del software. In questo caso la soluzione ideale è di utilizzare un sistema di licenziamento del tipo “per installare o avviare il programma deve essere inserita la chiave corretta”, come avviene per i software commerciali più noti (ad esempio Office o Windows stesso). Una possibilità è quella di usare il software TrueLicense:

http://truelicense.java.net/

Sul sito ufficiale potete trovare ampia documentazione in modo da usare correttamente il software e le licenze.

Qui c’è una lettura interessante su come proteggere un’applicazione Java facendo uso di chiavi/licenze:

http://stackoverflow.com/questions/10896596/protect-java-application-by-licence-or-key

Avendo un po’ di tempo a disposizione, potrebbe valere la pena implementare un proprio algoritmo per la generazione di una chiave. Ad esempio, una chiave univoca potrebbe essere generata a partire dall’indirizzo MAC della scheda di rete, essendo l’indirizzo stessa per sua natura univoco (a meno di manomissioni hardware). Di semplice utilizzo sono anche le funzioni hash, come SHA1, sufficientemente robuste, e possono essere sufficienti per le applicazioni più piccole.

3. Versione trial del software. Un’altra tecnica, che può essere usata per proteggere un’applicazione, è quella di crearne una versione demo/trial, o alternativamente di permetterne l’utilizzo solo per un periodo di prova limitato (10 giorni, 30, …).

Il software TrueLicense visto al punto precedente permette di creare anche licenze temporanee, che sono dunque valide per un periodo limitato di tempo, oltre il quale il software non può più essere adoperato. Per questa funzionalità potete vedere la documentazione ufficiale:

http://truelicense.java.net/tutorial.html#Using_the_Free_Trial_Period_FTP_Package

Al seguente link viene suggerita una soluzione “manuale” che permette di creare un’applicazione in versione trial:

http://stackoverflow.com/questions/2021088/implementing-a-30-day-time-trial/2022237#2022237

Buon codice a tutti ;-)…

Matteo

JaXy, un proxy HTTP in Java

Rendo disponibile per il download un proxy HTTP che ho scritto in Java.

Il proxy effettua le operazioni base di un proxy, supportando il protocollo HTTP 1.1 e rispettando l’RFC 2616:

1. il client (browser) richiede una risorsa (URL);
2. il proxy intercetta la richiesta;
3. il proxy controlla la propria memoria cache per vedere se può rispondere al client direttamente oppure se deve richiedere la risorsa (URL) al server finale;
4. il server finale risponde al proxy;
5. il proxy aggiorna la propria memoria cache con la risposta del server;
6. il proxy crea un nuovo pacchetto ed invia la risposta al client. […]

Rendo disponibile per il download un proxy HTTP che ho scritto in Java.

Il proxy effettua le operazioni base di un proxy, supportando il protocollo HTTP 1.1 e rispettando l’RFC 2616:

  1. il client (browser) richiede una risorsa (URL);
  2. il proxy intercetta la richiesta;
  3. il proxy controlla la propria memoria cache per vedere se può rispondere al client direttamente oppure se deve richiedere la risorsa (URL) al server finale;
  4. il server finale risponde al proxy;
  5. il proxy aggiorna la propria memoria cache con la risposta del server;
  6. il proxy crea un nuovo pacchetto ed invia la risposta al client.

Nella figura seguente è mostrata la logica del funzionamento di un proxy HTTP.

HTTP_Proxy_architecture
Funzionamento di un proxy HTTP

Da Wikipedia: “In computer networks, a proxy server is a server (a computer system or an application) that acts as an intermediary for requests from clients seeking resources from other servers. A client connects to the proxy server, requesting some service, such as a file, connection, web page, or other resource available from a different server. The proxy server evaluates the request as a way to simplify and control their complexity.

L’applicazione non è una servlet ma è un server stand-alone, dunque non necessita di servlet engine o container (come Tomcat).

L’applicazione si chiama JaXy, abbreviazione di Java Proxy, ed è scaricabile e utilizzabile secondo la licenza GPLv3 al seguente link:

JaXy-v0.1.tar.gz – Initial release (2012-06-20):

  • supporto per HTTP 1.1, secondo le specifiche dell’RFC 2616
  • interfaccia semplice a linea di comando
  • supporto per IPv4

Matteo

Chiavi a più colonne con phpMyAdmin

Al momento attuale con phpMyAdmin 3.5.1, durante la creazione di una tabella non è possibile specificare chiavi (Primary o Unique) costituite da più colonne. Dunque prima dobbiamo creare una tabella, e poi il metodo più veloce è […]

Al momento attuale con phpMyAdmin 3.5.1, durante la creazione di una tabella non è possibile specificare chiavi (Primary o Unique) costituite da più colonne. Dunque prima dobbiamo creare una tabella, e poi il metodo più veloce è:

  1. selezionare database -> tabella -> struttura
  2. spuntare le colonne della tabella che dovranno far parte della stessa chiave
  3. scegliere Primary o Unique a seconda del tipo di chiave che vogliamo creare

phpMyAdmin_chiavi_colonne_multiple

Matteo

Could not find the main class in Java

Se lanciando un’applicazione Java da terminale appare il seguente errore:

Java Virtual Machine Launcher.
Could not find the main class.
Program will exit.

il problema è molto probabilmente dovuto ad una configurazione errata della variabile d’ambiente CLASSPATH. Una soluzione è quella di configurare correttamente la variabile, mentre l’altra è quella di eseguire il programma Java con l’opzione -classpath: […]

Se lanciando un’applicazione Java da terminale appare il seguente errore:

Java Virtual Machine Launcher.
Could not find the main class.
Program will exit.

il problema è molto probabilmente dovuto ad una configurazione errata della variabile d’ambiente CLASSPATH. Una soluzione è quella di configurare correttamente la variabile, mentre l’altra è quella di eseguire il programma Java con l’opzione -classpath:

java -classpath . applicazione

dove applicazione rappresenta il nome del programma Java. In questo modo viene detto a Java che il classpath è la propria directory locale.

Una lista dei problemi più comuni con Java può essere trovata al link seguente:

http://www.dis.uniroma1.it/~figest/problemi.html

roghan

Eccezioni in Java: come gestirle correttamente

Oggi vediamo le eccezioni in Java, ma non spiegherò cosa sono (ci sono miliardi di documenti sul web al riguardo), piuttosto farò un po’ di chiarezza su quali tipi di eccezioni esistono e su come gestirle correttamente.

Brevemente, in Java un’eccezione è un evento che si può presentare durante l’esecuzione di un programma, e che interrompe il normale flusso delle istruzioni. A livello pratico, un’eccezione è un oggetto che viene creato al presentarsi dell’errore, e la gerarchia delle classi è visibile nella seguente figura, e ha come padre Throwable. […]

Oggi vediamo le eccezioni in Java, ma non spiegherò cosa sono (ci sono miliardi di documenti sul web al riguardo), piuttosto farò un po’ di chiarezza su quali tipi di eccezioni esistono e su come gestirle correttamente.

Brevemente, in Java un’eccezione è un evento che si può presentare durante l’esecuzione di un programma, e che interrompe il normale flusso delle istruzioni. A livello pratico, un’eccezione è un oggetto che viene creato al presentarsi dell’errore, e la gerarchia delle classi è visibile nella seguente figura, e ha come padre Throwable.

eccezioni_java
Gerarchia delle eccezioni Java

Ci sono 2 classi distinte: Error e Exception. A sua volta, la classe Exception può essere suddivisa in questo modo:

  • eccezioni controllate (checked): possono verificarsi indipendentemente dalle scelte del programmatore, per esempio un errore durante la lettura di un file.
  • eccezioni non controllate (unchecked): classi RuntimeException e Error. Possono verificarsi indipendentemente dalle scelte del client/utente, e possono invece dipendere dalla realizzazione di codice poco robusto, come ad esempio eccezioni NullPointerException (colpa del programmatore).

Questa distinzione è molto importante, perché ci dice quali sono le eccezioni da prendere in considerazione durante la scrittura di un programma e dunque quali sono le eccezioni da gestire. Come suggerisce giustamente il nome :-), le eccezioni controllate devono necessariamente essere gestite all’interno di un programma, con i canonici comandi try/catch, altrimenti il compilatore non sarà in grado di compilare con successo il codice. Le eccezioni controllate possono ad esempio essere generate con l’apertura di un file o di una risorsa (IOException), oppure con l’acceso o manipolazione di un database (SQLException), e le cause sono esterne al programma stesso. Per questo motivo il programmatore deve gestire adeguatamente le eccezioni di questo tipo, non sapendo se saranno sollevate (la risorsa può non essere disponibile, la connessione al database può essere stata interrotta, …). Un semplice codice di esempio può essere il seguente:

try {
//apertura file
}catch (FileNotFoundException fnfe)
{
System.err.println("FileNotFoundException: " + fnfe.getMessage());
}

Le eccezioni non controllate invece non devono obbligatoriamente essere gestite, in quanto non dovrebbero sollevarsi in presenza di codice ben scritto (tutti noi scriviamo codice robusto no?! ;-)). In ogni caso è bene controllare attentamente il codice scritto al fine di evitare brutte sorprese ed evitare assolutamente eccezioni del tipo: un puntatore è nullo (NullPointerException), è state effettuata una divisione di un numero per zero (ArithmeticException), … Ad esempio un codice come il seguente:

try
{
int x;//input fornito dall'utente
System.out.println(5/x);
}catch(ArithmeticException ae)
{
System.err.println(ae.getMessage());
}

dovrebbe essere sostituito con il seguente codice:

int x;//input fornito dall'utente
if(x == 0)
{
System.out.println("Errore: l'input fornito è errato. Non è accettato il valore 0.");
System.exit(1);
}else
{
System.out.println(5/x);
}

Per ulteriori approfondimenti sulle eccezioni in generale leggere:

roghan

Privilegi root per bind di porte 1-1023 in Java

Se dobbiamo creare un server in Java per accettare comunicazioni su TCP, è necessario usare la classe ServerSocket, mentre quella Socket è specifica per il lato client. Durante la creazione della componente client, bisogna fare particolare attenzione a quali porte indichiamo se ci troviamo su sistemi Linux/Unix. […]

Se dobbiamo creare un server in Java per accettare comunicazioni su TCP, è necessario usare la classe ServerSocket, mentre quella Socket è specifica per il lato client. Durante la creazione della componente client, bisogna fare particolare attenzione a quali porte indichiamo se ci troviamo su sistemi Linux/Unix. Ad esempio, il codice per mettere in ascolto un server sulla porta 80 è il seguente:

try
{
     ServerSocket server= new ServerSocket(80);
}catch (IOException iex)
{
     System.err.println(ex);
}

Il codice è corretto, ma potrebbe essere sollevata un’eccezione su sistemi Unix/Linux o anche Windows, in quanto sono necessari i privilegi di root/administrator per poter usare le porte nel range 1-1023.

roghan

Utility Java per convertire numeri esadecimali

Ho realizzato in Java una piccola utility da linea di comando che effettua la conversione di un numero decimale in uno esadecimale e viceversa. Prima di vedere come utilizzarla, vediamo brevemente cos’è un numero esadecimale, per chi non lo ricordasse ;-).

Da wikipedia: “Il sistema numerico esadecimale (spesso abbreviato come esa o hex) è un sistema numerico posizionale in base 16, cioè che utilizza 16 simboli invece dei 10 del sistema numerico decimale tradizionale. Per l’esadecimale si usano in genere simboli da 0 a 9 per le prime dieci cifre, e poi le lettere da A a F per le successive sei cifre, per un totale di 16 simboli.”
[…]

Ho realizzato in Java una piccola utility a linea di comando che effettua la conversione di un numero decimale in uno esadecimale e viceversa. Prima di vedere come utilizzarla, vediamo brevemente cos’è un numero esadecimale, per chi non lo ricordasse ;-).

Da wikipedia: “Il sistema numerico esadecimale (spesso abbreviato come esa o hex) è un sistema numerico posizionale in base 16, cioè che utilizza 16 simboli invece dei 10 del sistema numerico decimale tradizionale. Per l’esadecimale si usano in genere simboli da 0 a 9 per le prime dieci cifre, e poi le lettere da A a F per le successive sei cifre, per un totale di 16 simboli.

Nella seguente tabella è visibile la conversione da decimale a esadecimale a binario.

Ad esempio, se abbiamo il numero esadecimale 1F5A, possiamo effettuare la conversione in decimale nel seguente modo: (1 x 16^3) + (15 x 16^2) + (5 x 16^1) + (10 x 16^0) = 8026. Inoltre, spesso un numero esadecimale viene indicato anteponendo al numero 0x, specialmente nei sistemi Unix-like, diventando ad esempio 0x1F5A.

Nel momento in cui l’utility viene avviata con il comando HCT (acronimo di Hex Conversion Tool, la classe che contiene il main), viene fornito il seguente menu:

$ java HCT
                       _____________________________
                      /                             \
                     |      Hex Conversion Tool      |
                     |             v1.0              |
                      \_____________________________/

            [ Matteo Cappelli aka roghan | matcap83@libero.it ]

[ Options ]
 1 - convert decimal to hex
 2 - convert hex to decimal
 3 - exit

Choose an option:
|

L’utility, con la relativa documentazione javadoc, è scaricabile dal seguente link:

roghan