Minha intenção neste artigo é mostrar que podemos suprir a deficiência de segurança no método GET. Muitas pessoas acabam usando o método POST por ser mais seguro e confiável que o método GET, mas às vezes, por exemplo, quando você pega um sistema pronto e precisa fazer uma manutenção, é melhor você continuar usando o método GET do que trocar tudo por POST.
Depois de muito tempo analisando, resolvi deixar tudo como está, ou seja, usando o método GET. Porém, descobri que podia deixar o GET mais seguro. Mas como? Usando criptografia MD5.
Mas o que seria criptografia MD5?
O MD5 (Message-Digest algorithm 5) é um algoritmo de hash de 128 bits unidirecional desenvolvido pela RSA Data Security, Inc., descrito na RFC 1321, usado por softwares com protocolo ponto-a-ponto (P2P), verificação de integridade e logins. Ou seja, uma forma de criptografia, extremamente segura.
Mas informações sobre essa criptografia, você pode encontrar neste link:
Resumidamente, a principal parte do código são as funções get_rnd_iv() e md5_encrypt(), são essas duas funções responsáveis pela criptografia do ID que estou passando.
Note que não estou passando diretamente o ID que recebi do Banco de Dados. Primeiro criptografo ele para depois passar pela variável $id_cript, responsável por chamar a função md5_encrypt(). Veja também que existe um "password" que estou passando na função. Este password deve ser o mesmo tanto na hora de enviar os dados criptografados como na hora de receber os dados. Se este password estiver errado, os dados não serão decriptografados e a função não vai funcionar.
$id = md5_decrypt($id_cript, $password);
$con = new ConexaoMysql();
$result = $con->sql("SELECT * FROM clientes WHERE id = '$id'");
$dados = mysql_fetch_array($result);
$nome = $dados['nome'];
?>
Esta página recebe os parâmetros criptografados passados pela página index.php e decripta os parâmetros.
A função responsável por fazer isso é a md5_decrypt(). Note que mesmo estando em páginas diferentes, existe um password também nesta página, o mesmo password (123) que existe na página index.php.
A função verifica se os dados pertencem ao mesmo password. Os dados sendo do mesmo password, a função decripta as informações. Veja também, que logo depois de decriptar os dados, estou usando o mesmo dado para fazer uma consulta em uma tabela do meu Banco de Dados e o melhor, totalmente transparente ao usuário.
[1] Comentário enviado por Ragen em 25/06/2006 - 09:05h
Olá,
Legal o seu artigo =]
Mas gostaria de fazer um breve comentário. Fiquei analisando o código de encriptação por bastante tempo pra tentar entender com detalhes o que ele estava fazendo, mas então notei que seria injusto dizer que a solução é o md5. Na verdade o md5 é um "ator" do elenco de encriptação que desempenha um bom papel.
A lógica da criação dos packers/unpackers (base 16/hexadecimal) utilizando uma semente aletória em cima de uma base hexadecimal foi uma ótima sacada - Pois mata dois coelhos com uma cajadada só:
- O md5 empacota e desempacota o texto com o auxilio da funcao mt_rand(), que não utiliza a libc que por sua vez geralmente retorna sementes meio viciadas.
- O metodo de empacotamento/desempacotamento faz a colisão tender a zero.
[3] Comentário enviado por pacman em 25/06/2006 - 13:46h
Não sei se eu to sonolento mas achei que podia haver alguns comentários no código. Gostaria muito de implementa-lo assim que entender como ele funciona.
Fora isso, muito bom o artigo!
[4] Comentário enviado por ijv314 em 26/06/2006 - 00:03h
Ótimo artigo!
Nunca tinha visto algo sobre como criptografar o modo GET, que realmente facilita quando se necessita fazer uma montagem rápida de páginas!
Valeu!!
[5] Comentário enviado por tomashugo em 27/06/2006 - 09:11h
Bom o artigo, gostei muito, só não entendi direito o código.
Agora vai uma sugestão, se o usuário mudar o código já criptografado, na hora de desencripitar irá retornar algo inconsistente, podendo trazer problemas para a aplicação.
Existe alguma maneira de saber se o código gerado pela encriptação está 'corrompido'?
$valor=md5("teste");
$sql="select * from tabela where md5(campoDaTabela)=".$valor;
ou use direto o md5 do proprio banco ....
$sql="insert into tabela(senha) values (md5(".$_GET['senha']."))";
.....
$sql="select senha from tabela where senha=md5(".$_GET['senha'].")";
....
$sql="select md5(id) as id FROM tabela";
na minha opniao vale mais a pena tu nao saber os valores reais armazenados mas sim apenas as chaves, para depois comparar os dados para ver se as chaves batem do que este esquema de embaralhar (encriptar) e desembaralhar depois
[11] Comentário enviado por Ragen em 28/06/2006 - 12:03h
Como não cara?
É algo bastante trivial. Existem ferramentas hoje em dia que fazem Mass Brute Force, ou seja, você faz um cluster de 100 máquinas tentando achar a senha que você precisa sem muita dificuldade.
O processo é bem simples, como a senha em questão só precisa colidir com o hash - Teoricamente existem mais de 1 senha que possuem o mesmo hash. Em outras palavras, se você possui uma senha com 1 milhão de caracteres, existe a possibilidade de você tirar o hash de uma string com 10 caracteres e haver a colisão =]
[12] Comentário enviado por bestlinux em 28/06/2006 - 12:06h
"É algo bastante trivial. Hoje existem ferramentas hoje em dia que fazem Mass Brute Force, ou seja, você faz um cluster de 100 máquinas tentando achar a senha que você precisa."
Agora você disse tudo....100 maquinas em cluster....no minimo ;-)
[15] Comentário enviado por Ragen em 28/06/2006 - 12:19h
Citando o problema do artigo:
"Um dia destes estava fazendo manutenção em um sistema da empresa que trabalho. Estudei o código do sistema, e vi que o programador estava usando muito o método GET. Em vários momentos, o método GET era utilizado, principalmente na edição de algum dado.
Bom... não vi problema algum, mas meu superior viu vários problemas e realmente eles existiam e eram falhas muito problemáticas.
Falha:
O programador tinha feito um código parecido com este (isto é apenas um exemplo):
<?
$con = new ConexaoMysql();
$result = $con->sql("SELECT * FROM clientes");
$dados = mysql_fetch_array($result);
$linhas = mysql_num_rows($result);
$ini = 0;
Este é apenas um código básico que lista todos os clientes da minha tabela "clientes" e ao lado do nome do Cliente, contem um link para o administrador "Editar" o Cliente. Código clássico que muitos desenvolvedores quando estão com pressa acabam usando.
O sistema em que eu estava fazendo manutenção era um sistema muito mais complexo e o problema principal da falha é que poderia ocasionar impactos "financeiros" caso o usuário alterasse o parâmetro recebido pelo GET. E realmente, este é um dos maiores problemas do método GET: O usuário que altera o parâmetro na URL."
Eu gerando os hash's de 1 até 1 milhão teria fácil os id's que preciso entre essa faixa ;)
[17] Comentário enviado por cbov em 28/06/2006 - 12:37h
ragen, realmente a ideia que eu passei com inteiros não ajudaria neste caso
e lembrando que o algoritimo apresentado neste artigo usa uma chave para "embaralhar" as coisas o que para passar inteiros por GET resolveria bem o problema
[18] Comentário enviado por elgio em 05/06/2007 - 12:02h
Não chame o MD5 de algoritmo de criptografia. NÃO É! É de hash!
Criptografia seriam o DES, AES, RC5, ...
No teu caso não estás usando MD5 para criptografar (e nem poderia) mas sim um simples XOR. Estás usando o MD5 para gerar uma sequencia de bits para ser aplicada ao XOR (no caso 128 bits). Logo a segurança desta criptografia está no XOR e um ataque de forma bruta seria sobre ele, com todos os vícios do XOR (em caso de repetição da chave, quebra-se; em caso de usuário ter texto cifrado + texto claro, descobre tua senha, entre outros):
Onde ch é a chave, texto o texto claro.
( 3DES é super seguro, embora lento em relação aos novos como AES)
Vai no php.net Tem trocentos algoritmos de criptografia disponíveis. Ai sim estariamos fazendo com algoritmos FORTES (a segurança estaria na chave que ficaria exposta no codigo e que deve ser imprevisivel para resistir ao ataque de dicionario. Poderia usar como chave uma chave padrao+varios dados do $_SERVER, sendo a chave um hash md5 de tudo isto, ou sha1 para os que já olham o md5 de um jeito estranho...)
Se quiser mesmo ter uma segurança criptografica podes usar algoritmos reais de cifragem como o AES que já tem suporte no PHP. Para evitar usar sempre a mesma senha, poderia usar o IP de origem do cliente (ou alguma outra info do header dele) como PARTE da senha, assim clientes diferentes terão suas URL criptografadas de forma única.
[19] Comentário enviado por condelogan em 11/08/2007 - 22:47h
Um detalhe caro amigo: HASH é criptografia SIM. É a chamada criptografa de uma via. Como são resumos de plaintext, em teoria voce não pode obter o valor original atraves do resumo...Mas isso ocorre principalmente, com ataques de colisão, mas nosso amigo la em cima esta com a razão em falar que MD5 é facil de quebrar, para isso existem algoritmos de hash mais fortes como o SHA1 que o PHP oferece suporte, e gera um hash de 160 bits. Ja existem implementações em 256 bits e 512 bits....dependendo da forma como o desenvolvedor vai trabalhar, o site fica bem mais seguro, mas eu pessoalmente gosto de criar meus algoritmos de criptografia, para complicar um pouco mais e deixo hash apenas para critptografar senhas....
[20] Comentário enviado por condelogan em 12/08/2007 - 09:51h
ah, outra coisa, eu aceito o desafio para quebrar o md5, e ganhar os $100000,000 que o bestlinux ofereceu.....felizmente, tenho programa que quebra ele....e so lamento, mas md5 com seus 128 bits apenas ja esta totalmente desatualizado....
[21] Comentário enviado por elgio em 12/08/2007 - 18:47h
Caro Sandoval.
Me perdoe, mas precisarei discordar de você em dois pontos. Estou baseado em literatura e não em textos levianos da Internet.
O primeiro é a reafirmação de que MD5 não é algoritmo de criptografia. Neste ponto tu até mesmo concorda comigo quando diz que é de mão única. É isto mesmo! Uma "criptografia" que não tem volta e se não tem volta, não é criptografia. Por algoritmos de criptografia entende-se poder cifrar e decifrar e com a utilização de uma chave. O MD5 é um algorítmo de HASH (tem a sua própria denominação, como o SHA1). Algoritmos de HASH tem como características não terem chave, não serem reversíveis (o mão única) e gerarem sempre HASH de um mesmo tamanho, independente do tamanho do texto. Este tipo de algoritmo pode até usar um algoritmo de criptografia como base, como o DES, mas eles recebem sua própria denominação: HASH
Veja que estou falando de sutilezas técnicas.
O segundo ponto é sobre o MD5 poder ser quebrado.
Vos garanto que sou um profundo conhecedor do assunto, sei das recentes descobertas de colisões e dos algoritmos dos Indianos. Também CONCORDO contigo que devemos abandonar o MD5. Mas que ele foi QUEBRADO, isto não!
O programinha que tens para "quebrar" o MD5 certamente é por ataque de dicionário, tentando quebrar hashes de textos simples. Isto não é quebrar e pode ser realizado com qualquer algoritmo. O MD5 NÃO É FÁCIL DE QUEBRAR, pois iria requerer um esforço computacional de 2 elevado na 128. Não quer dizer que ele seja, atualmente, um algoritmo confiável, pois a descoberta de colisões (que é diferente de quebrar) é um risco.
Desculpe, mas eu não tenho 100 mil dolares, mas se tu conseguir quebrar este MD5
que gerei com md5sum, terei maior prazer em retirar tudo que eu disse (questão de HONRA pra ti):
Se tu prefere no formato senhas do LINUX, te forneço também:
$1$Z.X/3YpT$O4P58NKqKlswqJAImaeTb1
(AMBOS TEM O MESMO TEXTO como base)
Quebre-o e poste-o aqui, sendo que qualquer um vai poder testar se é verdadeiro. O primeiro com echo TEXTO|md5sum e o segundo com um mkpasswd -H md5 TEXTO Z.X/3YpT
Me entenda, não estou querendo criar nenhuma polêmica barata, mas é que teoria é teoria, realmente tenho muito conhecimento da area e o que se faz é muita confusão a respeito. Lembro tambem que estou DISCORDANDO de ti quando tu diz que o MD5 pode ser facilmente quebrado (sem fornecer em QUAL CONTEXTO, devo entender que SEMPRE), mas concordo quando dizes que devemos abandonar o MD5, pois um algoritmo que se descobriu muitos furos (nenhum deles que o torne QUEBRAVEL) não merece nossa confiança.
[22] Comentário enviado por elgio em 12/08/2007 - 18:55h
Ainda, sobre o DESAFIO.
bestlinux está com a razão!
Os site que "quebram" o MD5 e até mesmo o SHA1, não QUEBRAM, ora bolas!!
Eles apenas tem listas gigantescas de textos muito usados para os quais ele já conhece. Gere um HASH com a palavra "Teste123" e VOALÁ, eles quebram.
Mais uma vez, desafio qualquer um a usar a ferramenta que quiser, o site que achar e me digam QUAL É A SENHA deste HASH MD5:
$1$Z.X/3YpT$O4P58NKqKlswqJAImaeTb1
É preciso entender as coisas. Ataques de dicinário não tem nada a ver com força bruta. Até os mais fortes algoritmos de hash serão piada se o usuário colocar a placa do carro como senha!
[23] Comentário enviado por elgio em 13/08/2007 - 09:55h
Então temos um caso em que AMBOS estamos certos, sob pontos de vistas diferentes :-D
"Em todos estes livros, HASH é considerado Criptografia..."
Sim, pertence ao estudo da Criptografia. Ambos certos. Mas não serve para Criptografar - NÃO TEM CHAVE!!!
HASH pertence ao grupo de estudo das Criptografia, mas não serve para criptografar (pois não é reversível). Na verdade ambos dizemos a mesma coisa.
Se tu estudou a fundo algoritmos de criptografia e o MD5, deve saber que um esforço de 2 na 128 ainda é um sonho e isto seria o QUEBRAR por força bruta. Não quer dizer que não se possa tentar! Se começa com cars apenas numéricos e poucas letras e vai tentando, de acordo com a paciência de quem espera e do HW que ele tem. Até mesmo o RSA de 1024 (cujo esforço computacional equivale há um simétrico de 256) pode ser tentado por força bruta.
Mas de NADA VAI ADIANTAR o força bruta se o texto contiver caracteres misturados. Quando disse "CONTEXTO", quiz me referir ao força bruta, no sentido de que PARACEU que já existem algoritmos que quebram o MD5 por força bruta em tempo razoável e para QUALQUER tipo de texto, o que não é verdade. E isto não tem nada a ver com geração de colisões, que pode ser feito em segundos.
Agora é claro que para textos pequenos, como uma senha pequena de poucos caracteres (como tu mesmo a pouco contextualizou) nem só o MD5 como qualquer outro algoritmo será quebrado por força bruta, pois o força bruta será sobre um universo de poucos cars. Como disse, NENHUM algoritmo resiste se o carinha colocar a placa do carro como senha ou o seu aniversário. :-D
[24] Comentário enviado por elgio em 13/08/2007 - 09:59h
Ainda.
Analise a solução do nosso amigo, neste artigo.
Não concorda comigo que a Criptografia usada foi XOR?
Mas que o MD5 foi apenas usado para gerar um texto "aleatório" com o qual se fez o xor? Esta foi a origem da polemica.
Disse que não se pode usar o MD5 para criptografar e não se pode mesmo!
Tu não consegue descriptografar. :-D
(como no $iv = substr($block . $iv, 0, 512) ^ $password;
Isto é UM XOR!!!)
Novamente, ambos falando a mesma coisa, mas sob contexto diferentes.
[25] Comentário enviado por condelogan em 13/08/2007 - 15:58h
Concordo com você. Hash é capaz de criptografar, só não conseguirá decriptografar...Sobre a existencia de chave, existem soluções criptograficas(obviamente inseguras), que não utilização chaves para criptografar e nem para o processo inverso, a decriptografia.
Mas sobre a solução:
Apesar de muito interressante e utilizada(já vi ela em outros foruns tambem), não podemos chama-la de solução MD5, visto que ela não usa somente a função md5(), mas a função md5_encrypt() e md5_decrypt(), e varais outras como, base64_encode e base64_decode, e se fizermos:
Pessoalmente, eu usaria a função MCRYPT() - http://www.php.net/mcrypt - com o algoritmo Rijndael, ou a classe AES128, disponivel para download na internet com uma chave bastante segura.
[26] Comentário enviado por danilow em 19/10/2007 - 08:19h
Caro Diego,
creio que a função esteja com algum problema, quando codifico algo e depois decodifico fica aparecendo uns caracteres estranhos e também um "{TEXTO}"
Poderia checar por favor?
[27] Comentário enviado por dit0 em 11/12/2007 - 21:10h
Ola, cara essa solução sua vai me quebrar um galho, valeu mesmo, desse jeito podemos diminuir as vulnerabilidades causadas por scripts mal feitos ultilizando o GET. Parabéns.
[29] Comentário enviado por removido em 21/01/2009 - 18:41h
Amigos já trabalhei com Bruce Schneier ( ele nem sabe o que é criptografar ) e posso falar o md5 é um algoritimo de criptografia de via unica( hash ). Nem o mais poderoso computador do mundo consequer quebrar seque o hash md5 da string 'a', mais existe muitos dicionarios completos de md5 por ai o que passa a sensação de que o mesmo é inseguro.