Newsgroup: it.comp.java
Titolo: nascondere configurazione al cliente

Ciao a tutti, sto implementando una Tomcat Valve, ossia una classe java
che si occupa di intercettare tutte le richieste che arrivano al
server, allo scopo di controllare l'uso degli utenti sulla base dei
limiti imposti dalla licenza. La configurazione della valve si trova
nel file WEB-INF/context.xml e recita:
<Valve
  	className="com.ciccio.pasticcio.CPLicenseValve"
  	maxDuplicateUsers="2"
  	maxUsers="5"
  	userLifeCycle="120" />
Come potete immaginare il cliente non dovrebbe avere nessuna
difficolta' a editarsi il file per aumentarsi a piacimento il numero di
utenti collegati.
Potrei "cablare" il codice dentro la classe, ma e' una soluzione che
non mi piace, dovrei ricompilare per ogni cliente e per ogni licenza.
Pensavo di usare dei file di configurazione crittografati, ma prima di
mettermi in una impresa di tal fatta, vi chiedo se ci sono sistemi gia'
sperimentati e piu' facili per proteggere il proprio codice
grazie,
TREMALNAIK

> Pensavo di usare dei file di configurazione crittografati, 
Con file crittografati vai sul sicuro 
cosi solo tu potrai decifrarli.
Molti software a pagamento usano file crittografati.
Ciao
Max
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

 cosi solo tu potrai decifrarli.
Oppure aggiungi al file un 'checksum' in modo che se si cambia il file a 
mano il checksum non è più corretto. Ha il "vantaggio" di far vedere la 
config in chiaro, se è quello che ti serve. Ad es. weblogic di BEA fa 
così per la licenza.
bye
DKano

 così per la licenza.
E il checksum però va cablato nel codice, e si ritorna al punto di partenza
uL
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 E il checksum però va cablato nel codice, e si ritorna al punto di partenza
? La formula per calcolarlo si... forse non mi sono spiegato.
Intendevo qualcosa tipo:
<nome>pippo</nome>
<maxcli>2</maxcli>
<sum>3494783DEKOWE33</sum>
nel codice si cabla
String calcola(String nome, int maxcli)
che ritorna il checksum.
Se qualcuno altera a mano (mettendo 20 al posto di 2, ad es) il file il 
sum calcolato è diverso dal contenuto del campo 'sum' nel file quindi la 
config è errata.
bye
DKano

perchè dare la possibilità di modificare il numero di utenti,
una volta che hai scoperto che è stato alterato cosa fai??
con chi te la prendi?
io eviterei.


 
Con nessuno (perché tanto odio? :-) ), semplicemente avviso 
'configurazione alterata' e non faccio  proseguire.
bye
DKano

 ma se lo si altera 'a mano' l'applicazione se ne accorge.
grazie, mi piacciono le vostre idee, quella di Dkano però è più
facile...
TREMALNAIK

 'configurazione alterata' e non faccio  proseguire.
se non fai proseguire ok
anche se non ho ben capito come fai a controllare.


 
Il cliente "smanettone" si troverebbe costretto a ricorrere 
all'assistenza se, modificando "a mano" il file di configurazione, il 
software non dovesse piů avviarsi e restituire un messaggio d'errore. 
Oppure si troverebbe costretto a ripristinare i dati iniziali. CONTROLLO 
INDIRETTO.

 cosi solo tu potrai decifrarli.
ho visto un po' di esempi in rete, ma c'e' qualcosa che non mi e'
chiaro.... se l'applicazione deve de/crittare i files che utilizza
allora deve portarsi la chiave con lei. Ma allora il cliente potrebbe
decompilarsi il codice ed estrarsi la chiave, o no?
TREMALNAIK

 config è errata.
So come funziona un checksum, ma se lo metti in chiaro nel file basta
ricalcolarelo e sostituirlo. Non mi sembra un sistema molto resistente.
Se usi un checksum standard (e serio) è ovviamente facilissimo, basta
ricalcolarselo al volo e sostituirlo.
Se usi un checksum ad hoc, va fatto in modo che non sia banale. Per
"rompere" la protezione, supposto che l'algoritmo del checksum non sia
evidente, bisognerebbe o decompilare per vedere qual'è l'algoritmo o
utilizzare direttamente le tue classi per farglielo ricalcolare. Il
decompilare può essere reso difficile (ma ha comunque un costo, vedi
sotto), utilizzare direttamente le tue classi un po' meno perchè basta
tracciare l'applicazione per sapere cosa sta facendo quando valuta il
checksum (sotto linux un bel strace)
Per rendere le cose un filo più complesse invece il checksum potrebbe esso
stesso essere nascosto nel bytecode, come da mia mail precedente, invece
che in chiaro. Chiaramente devi poi trovare un modo per fare efficacemente
il deploying (che non sia ricompilare ogni volta).
E comunque devi offuscare il tutto, che è antipatico (modifiche al deploy,
decidere quali classi offuscare e quali no, eliminare eventuali parti
dinamiche, ecc.)
Insomma, non è facile farlo bene e con pochi fastidi, e comunque
impossibile farlo inviolabile


 facile...
Sarebbe piů robusto riuscire a cablare il numero di utenti nel codice (o
attaccarlo al bytecode in zone "morte" e:
- offuscarlo in qualche modo
- trovare un modo per fare il deploying 
in questo caso sarebbe molto piů difficile tracciare il codice, non si
avrebbe  l'hint del file.
hth


se vuoi criptare
ti giro una classe con due metodi
uno per criptare una stringa e uno per decriptare
cosi puoi creare una stringa inserirla nel file config
e decodificarla nel tuo applicativo.
il cript/decript utilizzano una key che puoi decidere tu e la lasci
nella classe "passPhrase"
ciao
max
import java.beans.Encoder;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.omg.IOP.Encoding;
public class CryptoService {
	Cipher ecipher;
    Cipher dcipher;
 
//    8-byte Salt
    byte[] salt = {
        (byte)0xA9, (byte)0x9B, (byte)0xC8, (byte)0x32,
        (byte)0x56, (byte)0x35, (byte)0xE3, (byte)0x03
    };
    // Iteration count
	int iterationCount = 19;
 
 
    public CryptoService() {
 
        try {
        	String passPhrase = "myKey";
//        	 
        	KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(),
salt, iterationCount);
            SecretKey key = SecretKeyFactory.getInstance(
                "PBEWithMD5AndDES").generateSecret(keySpec);
            ecipher = Cipher.getInstance(key.getAlgorithm());
            dcipher = Cipher.getInstance(key.getAlgorithm());
            // Prepare the parameter to the ciphers
            AlgorithmParameterSpec paramSpec = new
PBEParameterSpec(salt, iterationCount);
            // Create the ciphers
            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
            dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
        } catch (javax.crypto.NoSuchPaddingException e) {
        } catch (java.security.NoSuchAlgorithmException e) {
        } catch (java.security.InvalidKeyException e) {
        } catch (InvalidKeySpecException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidAlgorithmParameterException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
    public String encrypt(String str) {
        try {
            // Encode the string into bytes using utf-8
//            byte[] utf8 = str.getBytes("UTF8");
            byte[] utf8 = str.getBytes();
            // Encrypt
            byte[] enc = ecipher.doFinal(utf8);
            // Encode bytes to base64 to get a string
            return new sun.misc.BASE64Encoder().encode(enc);
        } catch (javax.crypto.BadPaddingException e) {
        } catch (IllegalBlockSizeException e) {
//        } catch (UnsupportedEncodingException e) {
//        } catch (java.io.IOException e) {
        }
        return null;
    }
    public String decrypt(String str) {
        try {
            // Decode base64 to get bytes
            byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
            // Decrypt
            byte[] utf8 = dcipher.doFinal(dec);
            // Decode using utf-8
//            return new String(utf8, "UTF8");
            return new String(utf8);
        } catch (javax.crypto.BadPaddingException e) {
        } catch (IllegalBlockSizeException e) {
        } catch (UnsupportedEncodingException e) {
        } catch (java.io.IOException e) {
        }
        return null;


 ti giro una classe con due metodi
troppo gentile... comunque ho visto che non c'e' un metodo realmente
sicuro per impedire all'utente di craccare il codice.
per fortuna ... ;)
TREMALNAIK

 sicuro per impedire all'utente di craccare il codice.
Esatto ora sei sulla strada giusta...
Bisogna premettere sempre che è IMPOSSIBILE (o quasi) realizzare una 
protezione (che sia per una licenza, un seriale, o dei file interni) che 
sia efficace al 100%...!
Tutto dipende da pochi fattori...
1) La complessità del sistema di protezione
2) L'originalità del sistema di protezione
3) Quanti utenti utilizzano quel programa
Andando per punti ma non in ordine, prestando attenzione al punto 
fondamentale (3):
3) Il numero di utenti interessati ad un certo programma lo rendono più 
utilizzato e logicamente con l'aumentare degli utilizzatori del 
programma...aumentano i bug...(che normalmente esistono in un 
programma...ma che non vengono scoperti da un ristretto numero di 
utenti...specialmente se di basso livello...) e aumentano anche i 
tentativi di COMPRENDERE...la struttura interna del programma...i 
significati di file, cartelle...fino ad arrivare alla decompilazione!
Il punto uno e due sono strettamente collegati tra di loro...un sistema 
anche se molto complesso...ma con una struttura già vista...poco 
innovatica...e non "artigianale" non è una buona resistenza 
all'aumentare del numero degli utenti!
(Quindi tenere segreto il sistema di protezione è anche una buona 
pratica...invece di andarlo a sbandierare in giro...come nel caso della 
protezione STAR-FORCE dei videogames...annunciata come "impenetrabile" e 
estremamente "sicura" e poi all'atto pratico è caduta dopo poco tempo!)
  ---> Un elevato numero di persone ha tentato di forzare la protezione 
finchè uno non c'è riuscito...e poi a macchia d'olio...su internet tutto 
si diffonde <---
*** Nonostante tutto questo è possibile rendere la vita un po' più 
difficile ai potenziali aggressori con tutta una serie di strumenti e 
tecniche ***
Ad esempio applicando insieme i vari layer di ofuscamento del 
codice...non rilasciare documentazioni troppo dettagliate...e tanto 
meno...javadocs troppo esaustive...e utilizzare quando serve anche la 
codifica del codice sorgente e dei file accessori.
Sfruttando anche una serie di Hash...un doppio controllo o cose 
simili...o sfruttare anche i vari serial number di componenti hardware 
del computer dell'utente da usare come chiavi di cifratura! :D
Ciao,
jRed
PS: Un po' lunghino...ma spero che serva a fare una bella 
panoramica...sul settore ---> Crack! :D