A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Informática Numaboa - Tutoriais e Programação

Como as senhas são criptografadas no Joomla

Seg

15

Dez

2008


22:25

(10 votos, média 5.00 de 5) 


Joomla

Meu amigo Tchó fez uma pergunta muito interessante: "Pretendo utilizar a tabela de usuários do Joomla para autenticar usuários em outras páginas que irei criar em um portal. Acontece que não sei como criptografar a senha digitada pelo usuário para comparar com a que está salva na tabela do BD do Joomla. Procurei muito pela Net mas ainda não encontrei... você poderia dar uma ajudinha?"

Claro que sim! E para que outros também possam usar estas informações, elas vão em forma de tutorial.

Antes de sujar a mão de graxa

Neste tutorial estou falando do método de encriptação de senhas do Joomla 1.5.x. Para reforçar a segurança deste CMS, estas versões apresentam um método bem mais robusto quando comparado com o método oferecido pelas versões mais antigas 1.0.x. Se você ainda não atualizou para a 1.5.x, está mais do que na hora de pensar em fazer isto - não só pelo aspecto segurança, mas também porque as versões 1.0.x vão ser descontinuadas.

Onde estão guardadas as informações

Não fui eu quem inventou o sistema de criptografia de senhas do Joomla, mas, como a criptografia é um dos meus assuntos preferidos, fui dar uma espiada no que a turma dos joomleiros fez. Localizei dois arquivos essenciais para entender a mecânica da cifragem: o primeiro é o arquivo joomla.php, que faz parte do plugin de autenticação; o segundo é o helper.php, que faz parte do conjunto de arquivos user da biblioteca joomla. Estão nos seguintes diretórios:

  • /plugins/authentication/joomla.php
  • /libraries/joomla/user/helper.php

Inicialmente abra o joomla.php e dê uma olhada no método onAutheticate:

/** * This method should handle any authentication and report back to the subject * * @access public * @param array $credentials Array holding the user credentials * @param array $options Array of extra options * @param object $response Authentication response object * @return boolean * @since 1.5 */ function onAuthenticate( $credentials, $options, &$response ) { jimport('joomla.user.helper'); // Joomla does not like blank passwords if (empty($credentials['password'])) { $response->status = JAUTHENTICATE_STATUS_FAILURE; $response->error_message = 'Empty password not allowed'; return false; } // Initialize variables $conditions = ''; // Get a database object $db =& JFactory::getDBO(); $query = 'SELECT `id`, `password`, `gid`' . ' FROM `#__users`' . ' WHERE username=' . $db->Quote( $credentials['username'] ) ; $db->setQuery( $query ); $result = $db->loadObject(); if($result) { $parts = explode( ':', $result->password ); $crypt = $parts[0]; $salt = @$parts[1]; $testcrypt = JUserHelper::getCryptedPassword($credentials['password'], $salt); if ($crypt == $testcrypt) { $user = JUser::getInstance($result->id); // Bring this in line with the rest of the system $response->email = $user->email; $response->fullname = $user->name; $response->status = JAUTHENTICATE_STATUS_SUCCESS; $response->error_message = ''; } else { $response->status = JAUTHENTICATE_STATUS_FAILURE; $response->error_message = 'Invalid password'; } } else { $response->status = JAUTHENTICATE_STATUS_FAILURE; $response->error_message = 'User does not exist'; } }

Não é preciso destrinchar este código todinho (o que seria uma chatice), vou apenas apontar as partes que nos interessam. As linhas 70 a 78 mostram que o plugin acessou o banco de dados do Joomla para buscar algumas informações na tabela de usuários filtrando os dados pelo nome de usuário. Depois disto, se tiver encontrado alguma coisa, explode o que encontrou no campo password usando o delimitador ":" (linha 82). A primeira parte (a senha criptografada) é armazenada na variável $crypt; a segunda (o chamado sal) é colocada na variável $salt. Isto indica que as senhas guardadas são compostas por duas partes. Alguns exemplos são:

3291503d0bd0059c54b466049594c443:Tk7F78S1VpAAGgPB 69a02eba32f545982806168859ebb08b:kQFgQ54RngbuYhsC

Logo a seguir, o método getCryptedPassword, que pertence à classe JUserHelper, é chamado com os parâmetros senha e sal (veja na linha 85). O que faz e onde está esta função? Na biblioteca do Joomla, mais especificamente no segundo arquivo que nos interessa: /libraries/joomla/user/helper.php. Veja a seguir o que são estas duas partes e como devem ser tratadas para que possamos conferir se determinado usuário está fornecendo a senha correta.


A criptografia das senhas do Joomla

No Joomla 1.0.x as senhas são transformadas num hash MD5. Se você não sabe o que é um hash, sugiro que dê uma lida nos artigos que publiquei em Criptografia/Funções Hash. Na versão atual, este hash foi incrementado (entenda-se, a segurança foi reforçada) adicionando-se um pouco de tempero, o chamado salt. A coisa funciona mais ou menos assim: "encomprida-se" a senha com mais uma porção de bits e só depois se aplica o hash MD5. Acontece que, se não soubermos qual salt foi usado para temperar a senha, não tem como repetir o processo para poder comparar a senha recém-fornecida com a senha que está no banco de dados. Daí separar a senha que foi "hasheada" junto com o sal do sal propriamente dito com o delimitador ":". Se tivermos os dois, o novo "hasheamento" pode ser comparado com o armazenado smile

Quem pode nos contar como todo este processo é realizado é o método getCryptedPassword da classe JUserHelper:

/** * Formats a password using the current encryption. * * @access public * @param string $plaintext The plaintext password to encrypt. * @param string $salt The salt to use to encrypt the password. [] * If not present, a new salt will be * generated. * @param string $encryption The kind of pasword encryption to use. * Defaults to md5-hex. * @param boolean $show_encrypt Some password systems prepend the kind of * encryption to the crypted password ({SHA}, * etc). Defaults to false. * * @return string The encrypted password. */ function getCryptedPassword($plaintext, $salt = '', $encryption = 'md5-hex', $show_encrypt = false) { // Get the salt to use. $salt = JUserHelper::getSalt($encryption, $salt, $plaintext); // Encrypt the password. switch ($encryption) { case 'plain' : return $plaintext; case 'sha' : $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext)); return ($show_encrypt) ? '{SHA}'.$encrypted : $encrypted; case 'crypt' : case 'crypt-des' : case 'crypt-md5' : case 'crypt-blowfish' : return ($show_encrypt ? '{crypt}' : '').crypt($plaintext, $salt); case 'md5-base64' : $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext)); return ($show_encrypt) ? '{MD5}'.$encrypted : $encrypted; case 'ssha' : $encrypted = base64_encode(mhash(MHASH_SHA1, $plaintext.$salt).$salt); return ($show_encrypt) ? '{SSHA}'.$encrypted : $encrypted; case 'smd5' : $encrypted = base64_encode(mhash(MHASH_MD5, $plaintext.$salt).$salt); return ($show_encrypt) ? '{SMD5}'.$encrypted : $encrypted; case 'aprmd5' : $length = strlen($plaintext); $context = $plaintext.'$apr1$'.$salt; $binary = JUserHelper::_bin(md5($plaintext.$salt.$plaintext)); for ($i = $length; $i > 0; $i -= 16) { $context .= substr($binary, 0, ($i > 16 ? 16 : $i)); } for ($i = $length; $i > 0; $i >>= 1) { $context .= ($i & 1) ? chr(0) : $plaintext[0]; } $binary = JUserHelper::_bin(md5($context)); for ($i = 0; $i < 1000; $i ++) { $new = ($i & 1) ? $plaintext : substr($binary, 0, 16); if ($i % 3) { $new .= $salt; } if ($i % 7) { $new .= $plaintext; } $new .= ($i & 1) ? substr($binary, 0, 16) : $plaintext; $binary = JUserHelper::_bin(md5($new)); } $p = array (); for ($i = 0; $i < 5; $i ++) { $k = $i +6; $j = $i +12; if ($j == 16) { $j = 5; } $p[] = JUserHelper::_toAPRMD5((ord($binary[$i]) << 16) | (ord($binary[$k]) << 8) | (ord($binary[$j])), 5); } return '$apr1$'.$salt.'$'.implode('', $p).JUserHelper::_toAPRMD5(ord($binary[11]), 3); case 'md5-hex' : default : $encrypted = ($salt) ? md5($plaintext.$salt) : md5($plaintext); return ($show_encrypt) ? '{MD5}'.$encrypted : $encrypted; } }

A função getCryptedPassword (linha 106) precisa no mínimo de um parâmetro: a senha em texto claro ($plaintext); os outros três parâmetros são opcionais. Se o sal ($salt) não for fornecido, ele recebe uma string vazia; se o tipo de encriptação ($encryption) não for definido, o valor padrão 'md5-hex' é assumido e se mostrar o tipo de encriptação ($show_encrypt) não for especificado, o padrão será falso. Em princípio, se chamarmos a função apenas com a senha fornecida pelo usuário, o sal não será usado, o tipo de cifragem será md5-hex e o tipo de encriptação não será adicionado ao resultado. É a cifragem mais simples que existe.

As linhas restantes desta função tratam de identificar o tipo de encriptação solicitado e realizam a cifragem de acordo. Para nós interessam apenas as linhas finais, onde o hash do tipo md5-hex é calculado. Se o sal estiver presente, a variável $encrypted recebe o valor de retorno da função do PHP md5() aplicada ao conjunto $plaintext.$salt; se não estiver presente, a mesma função do PHP é aplicada apenas a $plaintext. Da mesma forma, se $show_encrypt for verdadeiro, o tipo de cifragem é adicionado ao resultado pela concatenação de '{MD5}'.$encrypted; caso contrário, o valor de retorno será apenas o hash obtido.


Usando o banco de dados do Joomla fora do contexto Joomla

Agora que sabemos como as senhas são encriptadas antes de serem colocadas na tabela users é possível criar um código PHP próprio que busque informações no banco de dados do Joomla, fazer cifragens de senhas fornecidas pelos usuários e comparar os resultados. Digamos que temos um formulário com os campos usuario e senha. Este formulário aciona um script PHP que irá fazer a autenticação.

A primeira providência é buscar dados na tabela users. Para acessar o banco de dados do Joomla é preciso criar uma conexão:

Precisamos encontrar a senha cifrada do usuário indicado no formulário:

Tendo a senha criptografada, agora é preciso cifrar a senha fornecida pelo formulário e comparar as duas. Se a senha foi criptografada com um salt, sabemos que ela é composta por duas partes separadas pelo delimitador ":"; se não foi usado um salt, o delimitador não existe. Aqui podemos pegar uma carona no código do plugin para obter as partes da senha armazenada no banco de dados e depois completar o script com uma pequena rotina que cifra a senha fornecida pelo usuário e compara o resultado com a senha do banco de dados:

É claro que este script pode (e deve) ser melhorado. Por exemplo, deveria haver tratamento de erros como falha na conexão, etc. Mas este é apenas um esqueleto de script que serve somente para passar a idéia de como podemos implementar um sisteminha de checagem de senhas armazenadas no banco de dados do Joomla.

Grande abraço da vovo

mfx broker выплатыкупить чугуноккомпания ооо полигон возрождениеtranslate toдтп харьков видеотелефон никас

Informações adicionais