Vulnerabilidades em java - como resolver?

Prezados,

Pesquisando na internet sobre como tratar de segurança em código java, encontrei o seguinte link ftp://ftp.registro.br/pub/gts/gts0204/gts0204-01slides-seg-prog-java.pdf

Um dos assuntos que tenho muito interesse no que se refere às vulnerabilidades do java é sobre a exposição dos bytecodes. Como soluções para isso, o artigo cita o seguinte:

  1. Adição de código não funcional ao código fonte.
  2. Ofuscação do código fonte.
  3. riptografia dos arquivos compilados (.class).
  4. Esconder os arquivos compilados (.class).

Quanto ao item 2 (ofuscação), conheço o programa proguard que realiza essa tarefa.
E quanto aos demais itens? Algúem conhece, pode dar uma ajuda de como fazer?

O que seria um código não funcional e como adicioná-lo ao código fonte? Algum exemplo?
Como criptografar e esconder os arquivos compilados?

Há algum material (talvez um livro) que trate desses assuntos?

Ficarei muitíssimo grato se alguém puder ajudar.

Saudações.

Olá André, também tenho bastante interesse nesse assunto. Fiz uns testes no proguard e confesso que não me agradou muito, ele da uma embaralhada boa no código, mas com um pouco de paciência e persistência da pra pegar o que quiser dentro do fonte. Ele não é muito eficaz!

Estou a procura de algo mais eficiente, se eu encontrar eu mando para você.

[]'s

[quote=mauricioadl]Olá André, também tenho bastante interesse nesse assunto. Fiz uns testes no proguard e confesso que não me agradou muito, ele da uma embaralhada boa no código, mas com um pouco de paciência e persistência da pra pegar o que quiser dentro do fonte. Ele não é muito eficaz!

Estou a procura de algo mais eficiente, se eu encontrar eu mando para você.

[]'s[/quote]

Olá, Mauricio. Obrigado por responder.

Poxa, no aspecto ofuscação do código, eu estava confiante no proguard.

Qual programa você utilizou em seus testes para a descompilação?

usei o plugin JDecompiler. ele cria umas classes com nomes esquisitos, mas da pra ver o codigo normalmente.

Eu tenho usado o Netbeans. Esse plugin JDecompiler serve para o netbeans?

Deixa eu ver se entendi.
Após gerar as suas classes, você as submeteu ao proguard e posteriormente as descompilou com o JDecompiler?
E foi possível entender o código?

O que um ofuscador, como o proguard, faz é tirar a legibilidade do seu código. Ao ofuscar, ele remove comentários, insere quebras de linha, cria classes e métodos com nomes como ac123__aaaa, e por ai vai.
Assim, quem descompilar seu programa vai ver um monte de arquivos sem significado.

Criptografia de classloader não é muito eficiente, se alguém tiver acesso à memória da máquina que está rodando a aplicação, com o uso de um dump da memória e algum esforço é possível quebrar o fonte do seu programa.

Eu tenho usado o Netbeans. Esse plugin JDecompiler serve para o netbeans?

Deixa eu ver se entendi.
Após gerar as suas classes, você as submeteu ao proguard e posteriormente as descompilou com o JDecompiler?
E foi possível entender o código?
[/quote]

fiz exatamente isso, compilei, passei o proguard, depois descompilei e olhei o codigo. Fica como o amigo matheuslmota disse, ele confunde os nomes das variaveis e gera umas classes extras com nomes estranhos, mas nada de muito eficiente.

[]'s

O problema desta “exposição” do código fonte java é inerente à sua arquitetura.

O que você decompila não é código fonte, mas sim bytecodes decompilados. Porém , as bibliotecas java foram feitas para serem intercambiáveis rapidamente, e por isto expõem o contrato de interface de seu conteúdo.

Explico:

Em uma dll do windows, por exemplo, em que você tem o método “FazIsto(int x, double y, String z)”, “FazAquilo(String w, double z)” e “FazAquiloOutro(int X, String y, String z).”, tudo o que você vai enxergar ao abrir a API é

“método1”. “metodo2” e “metodo3”. Ele não expõe a ordem dos parâmetros ou o tipo de parâmetros necessários. Nem expõe se o método1 é o “FazIsto” ou “FazAquiloOutro”.

Porém, nos bytecodes java já estão implícitos quais são os métodos e quantos parâmetros são necessários.

Esta característica do java fornece muitas vantagens: um dos principais motivos de crashes de aplicativos vêm da incompatibilidade entre interfaces esperadas pela aplicação cliente x fornecida pelo fornecedor.

Por outro lado, isto facilita muito a leitura do código.

Outro ponto que favorece a decompilação do java é que há uma centralização na especificação da Java Virtual Machine, e quase um monopólio prático nos compiladores da Oracle.

Porém, eu já tive o desprazer de encontrar um jar totalmente criptografado. A única coisa que consegui retirar do conteúdo é o fato de que foi utilizada a api bouncycastle (bouncycastle.org) na sua criptografia. Talvez isto seja um bom ponto de partida.

Para quem sabe inglês, encontrei este artigo: http://www.javaworld.com/javaqa/2003-05/01-qa-0509-jcrypt.html?page=2

Ele coloca dois pontos importantes:

  1. É possível criar um ClassLoader que efetua descriptografia de arquivos. Assim, é possível criptografar um arquivo .class e usar um ClassLoader específico para descriptografá-la. Assim, simplesmente descompactar o jar e decompilar os .class não é mais algo possível.

  2. Mesmo com este recurso ainda é possível fazer algumas tramóias se você tiver controle sobre a execução da java virtual machine.

Ou seja, se seu código realmente tiver informações sensíveis (que permitiriam fraudes, por exemplo), você não deveria enviá-lo para seu cliente.

Nota: A solução acima certamente resolve contra o acesso casual por curiosos.

[quote=abmpicoli]É possível criar um ClassLoader que efetua descriptografia de arquivos. Assim, é possível criptografar um arquivo .class e usar um ClassLoader específico para descriptografá-la. Assim, simplesmente descompactar o jar e decompilar os .class não é mais algo possível.
[/quote]

mas se o classloader ta lá, o q impede o cara ver como ele faz a descriptografia?
creio q o tal classloader não está criptografado. e se está, quem descriptografa ele?

então esse “não é mais algo possível.” tem q ser repensado.

mas pra descompilar não precisa do fonte e sim do class. é não?

o cara q escreveu o pdf do link informado no primeiro post, é mt ruim hein!!!

não entende nada de “outras linguagens” e não sabe o q é “SQL injection”.

embora se atreveu a escrever como quem se passa por mestre no assunto.

Não é vulnerabilidade…isso é filosofia! kkkkkk
Não culpe Java por isso…se vc quer VENDER o software e fazer com que o CLIENTE COMPRADOR não tenha acesso ao fonte (se o cara ta comprando não seria dele uma copia???)…selecione uma outra plataforma que te oferece isso.
Se for usar Java, modelo de aplicativos web cumprem isso. O cliente usa o sistema via navegador, fazendo com que o código fique dentro do um servidor.

[quote=FernandoFranzini]Não é vulnerabilidade…isso é filosofia! kkkkkk
Não culpe Java por isso…se vc quer VENDER o software e fazer com que o CLIENTE COMPRADOR não tenha acesso ao fonte (se o cara ta comprando não seria dele uma copia???)…selecione uma outra plataforma que te oferece isso.
Se for usar Java, modelo de aplicativos web cumprem isso. O cliente usa o sistema via navegador, fazendo com que o código fique dentro do um servidor.[/quote]

então desktop é fora de coagitação?

Alguns “poréns” sobre a ofuscação em Java:

  1. Ele só vai deixar ilegíveis as suas classes. Classes das bibliotecas que você usa, ou as do próprio java, continuam legíveis;
  2. Ofuscação de bytecode != ofuscação de arquivos interpretados (como javascript). Então, não existe inserção ou remoção de quebras de linhas, afinal, bytecodes não tem linhas - são arquivos binários. Os comentários desaparecem também por conseqüência da compilação, não necessariamente da ofuscação. Os descompiladores reconstituem o código e o reformatam.
  3. Você não pode usar o ProGuard se seu código depende de reflexão sem annotations, como é o caso do Hibernate se configurado por xml. Caso contrário, tudo se perde. Mesmo no caso de annotations, cuidado com as anotações do tipo String, como mappedBy.
  4. Annotations normalmente não podem ser ofuscadas.

O código fica bastante ilegível, mas com recursos de IDEs modernas, tais como renomear variáveis e métodos, ainda pode ser revertido com relativa facilidade (não por um scriptkid, mas um programador que realmente queira roubar seu segredo industrial fará isso facilmente). Se o seu produto é crítico e o segredo dele está em seu algoritmo fantástico, use uma linguagem compilada, como C++, ou mantenha-o atrás de um servidor.

Outra é a possibilidade de fazer reflexão e inspeção via código.

De código fechado, sim.
De código aberto, não.

[quote=GilsonNunes][quote=abmpicoli]É possível criar um ClassLoader que efetua descriptografia de arquivos. Assim, é possível criptografar um arquivo .class e usar um ClassLoader específico para descriptografá-la. Assim, simplesmente descompactar o jar e decompilar os .class não é mais algo possível.
[/quote]

mas se o classloader ta lá, o q impede o cara ver como ele faz a descriptografia?
creio q o tal classloader não está criptografado. e se está, quem descriptografa ele?

então esse “não é mais algo possível.” tem q ser repensado.

mas pra descompilar não precisa do fonte e sim do class. é não?[/quote]

Má expressão minha. Se o seu código binário tiver informações sensíveis, por exemplo, métodos frágeis de criptografia, que ao descompilar entregam toda a segurança de sua aplicação, você não deveria enviá-lo para seu cliente.

Quanto à questão do classloader: como o próprio artigo que indiquei explica, o fato do classloader por si só ter que ser um programa não criptografado indica a possibilidade de um programador paciente, esperto e experiente descriptografar as classes e fazer engenharia reversa. Porém, isto é muito trabalho para um programador casual, a não ser que você use processos de criptografia muito ruins.

Outro ponto: se alguém está obstinado a fazer engenharia reversa do seu código binário, não importa a linguagem na qual você programe, este risco sempre vai existir. Afinal, em algum momento o computador terá que ler o seu código binário.

Reforço o que o ViniGodoy disse: se você não quer expor seu código binário para o cliente, mantenha-o em um servidor.

pq mt trabalho? o serviço ta feito. o classloader.
e não é questão de o cara “desvendar”, vc pode fazer a criptografia mais extraordinária de tdas. mas vc precisa colocar o mecanismo e forma de descriptografia lá.
então ele não precisa fazer nada. já tá lá.

e concordo com vc. qq coisa se descompila.

porém:

push %ebp mov %esp,%ebp sub $0x38,%esp mov %eax,-0x8(%ebp) mov %edx,-0x4(%ebp) movl $0x0,-0x10(%ebp) lea -0x1c(%ebp),%ecx lea -0x34(%ebp),%edx mov $0x1,%eax call 0x40bd30 call 0x40dad0 push %eax test %eax,%eax jne 0x424f59

é mt diferente de:

[code] public void run() {
int i = 0;
while (true) {
i++;
synchronized (a.this.a)
{
System.out.println("beginWrite: " + i);
for (int j = 0; j < a.this.a.length; j++) {
a.this.a[j] = i;
}
System.out.println("endWrite: " + i);
}
a.b(3000);

      if (i > 10)
        i = 0;
    }
  }
}

[/code]

Realmente, qualquer coisa se descompila. No caso do java o serviço é realmente facilitado por causa da estrutura da Java Virtual Machine, que possui muitas coisas em cleartext.

Porém, decompiladores tipicamente detectam padrões usados na compilação do código. Então, se você souber em que compilador um produto foi gerado, pode encontrar um decompilador para aquele produto. E você terá muitas estruturas similares ao que se obtém com um decompilador java.

Não dá, porém, para fazer coisas “malucas demais” no java, tais como apontar a execução para um trecho de dados recém descriptografado. Isto é muito bom para proteger seu código, porém é uma grande forma de se esconder código malicioso. E isto é um dos motivos pelos quais isto não é habilitado no java.

Bom, estamos realmente batendo em cachorro morto aqui, não? Quer esconder seu código, vá fazer umas maluquices em C… ou C++…

[quote=andredf]Prezados,

Pesquisando na internet sobre como tratar de segurança em código java, encontrei o seguinte link ftp://ftp.registro.br/pub/gts/gts0204/gts0204-01slides-seg-prog-java.pdf

Um dos assuntos que tenho muito interesse no que se refere às vulnerabilidades do java é sobre a exposição dos bytecodes. Como soluções para isso, o artigo cita o seguinte:

  1. Adição de código não funcional ao código fonte.
  2. Ofuscação do código fonte.
  3. riptografia dos arquivos compilados (.class).
  4. Esconder os arquivos compilados (.class).

Quanto ao item 2 (ofuscação), conheço o programa proguard que realiza essa tarefa.
E quanto aos demais itens? Algúem conhece, pode dar uma ajuda de como fazer?

O que seria um código não funcional e como adicioná-lo ao código fonte? Algum exemplo?
Como criptografar e esconder os arquivos compilados?

Há algum material (talvez um livro) que trate desses assuntos?
[/quote]

Existe um livro bom sobre isto chamado Covert Java.

Agora, tem coisas e tem coisas.

As pessoas normalmente esquecem que o que elas vendem não é software, são as licenças de uso.
Quem vende o software de fato , vc vendo o codigo e os direitos.

A licença é uma forma de transferir direitos. Especialmente o direito de uso.

No antigamente os programas vinha com mecanismos chamados de “licença”. Isto é a representação eletrónica da licença legal que o usuário adquiriu.

A licença também é onde se estipula o que não se pode fazer e um dos exemplos dos programas clássicos semrpe foi “Vc não pode decompilar este codigo”.

Portanto, a forma correta, real, que funciona, para proteger o codigo é a lei. Qualquer um que copie, decompile, etc. o codigo estará violando a lei e portanto vc pode processá-lo por isso. Não é uma questão de proibir que ele viole, é saber quando foi violado.

Por outro lado, segurança é tudo sobre o prémio. Quando o prémio é grande o suficiente o adversário tentará o acesso ilegitimo. Portanto, o sistema de segurança tem que tornar o acesso mais caro que o prémio. Tão simples assim. Ele não precisa garantir que não haverá violação, apenas que o advesário pagará por ela, mais que o prémio.

Portanto, ofuscar o código e depois encriptá-lo é uma opção melhor que não fazer nada. A classe que desencripta é aberta (não encriptada) mas não faz mal. Afinal o algoritmo de desincritação já é publico. Basta então que o classloader necessite de um arquivo com a chave correta. Essa chave é uma forma de licença. A chave em si pode ser submetida a um processo de legitimação que garante que apenas aquele usuário tem a licença certa. Isto é possivel mas complexo. Uma forma é fazer o software se auto autenticar (como o windows faz) de forma que não haja intervenção humana. Contudo, algum informação do cliente será necessária.
Um algortimo de chave privada-publica é obviamente mandatório isto porque mesmo que o cara desencript a coisa não consigue encriptar de volta.

Mas a segurança é mais do isto. Se for possivel, começar com nem sequer dar acesso ao código. hoje em dia o SaaS é famoso porque permite exactamene isto (entre outras coisas).

O ponto é :difculte se quiser, mas é tudo uma questão de prémio. Se vc tivesse um software que descobre os numeros de mega-sena com certeza o cara não vai parar até crackar , mas ninguém vai crackar a serie de fiboncci ou um gerador aletório. Talvez vc pense que o seu software é a oitava maravilha e ninguém mais pense isso.

Veja que mesmo um codigo C é crackavel - antigamente os caras crackavam todos os jogos. O que a industria fez ? jogos online onde sequer vc sabe onde fica o executável. Isto para dizer que não a plataforma ou a linguagem que são vulneráveis, é a arquitetura e o design.