Follow _ricardomaia on Twitter Visualizar perfil de Ricardo Maia no LinkedIn

Protegendo senhas de banco de dados

Uma questão comum que aflige muitos desenvolvedores PHP é como proteger as senhas de conexão com o banco de dados. Este problema não é exclusivo das linguagens interpretadas. Embora pareça mais seguro, linguagens compiladas também sofrem deste problema.

Antes de qualquer coisas quero abordar duas premissas:

  • A segurança é inversamente proporcional a usabilidade. Quanto mais níveis de segurança, mais difícil será de acessar e usar o recurso.
  • Às vezes não é preciso armazenar um segredo.

Tendo essas duas premissas em mente, apresento algumas opções:

1ª Opção – Senha no banco de dados: Você pode fazer com que a senha que conecta sua aplicação ao banco seja fornecida pelo usuário durante o login. O usuário da aplicação seria também um usuário de conexão com o banco.

Prós: Você pode aplicar restrições de acesso (ACL) a tabelas, views e funções criando mais um nível de segurança.  A senha não fica na aplicação e o usuário da aplicação não se conecta ao banco por meio de um usuário de banco com permissões muito maiores que as necessárias.

Contras: Provavelmente você terá de desenvolver alguma ferramenta abstração / interface entre suas regras de negócio e as respectivas permissões em banco de dados.

2ª Opção – Senha em memória compartilhada: A senha de conexão com o banco teria de ser informada pelo administrador ao inicializar a aplicação. A partir de então um hash poderia ser armazenado em memória compartilhada. Você pode utilizar as  funções de memória compartilhada do PHP para implementar uma solução como esta.

Prós: A senha não fica na aplicação. Você não precisa armazenar o segredo.

Contras: Deve se ter um cuidado para que outras aplicações no mesmo servidor não manipulem ou leiam indevidamente esta área de memória compartilhada.

3ª Opção – Autenticação externa (LDAP, Active Directory, PAM): Esta é uma variante da 1ª opção. Nela o usuário informa uma senha por meio da aplicação que é repassada ao banco, mas o banco de dados por sua vez fará a verificação das credenciais em uma fonte externa, como um Active Directory.

Prós: A senha não fica na aplicação.

Contras: Utilizar uma fonte externa pode causar inconsistências, pois sua aplicação não tem qualquer controle sobre a administração dos usuários.

4ª Opção – Registro do Windows: É como manter a senha em um arquivo de configuração.

Prós: A senha não fica junto do código. Uma senha específica para os ambientes de desenvolvimento, teste, homologação e produção já estariam configuradas no servidor.

Contras: Requer Windows e o uso de funções COM no PHP. Pessoalmente não gosto pois a solução está amarrada a um Sistema Operacional específico e exige elevado nível de privilégio do usuário que executa os processos do servidor web. Se preferir esta abordagem você pode utilizar a classe w32registry para facilitar o seu trabalho.

5ª Opção – Arquivo de configuração: É a opção mais simples e comumente utilizada. Um arquivo de configuração .INI ou .PHP. É recomendável que este arquivo esteja fora do diretório web.

Prós: A senha não fica acoplada ao código-fonte. Facilidade de uso. O Zend Framework por exemplo utiliza esta abordagem. É uma opção razoavelmente segura se as configurações de acesso ao arquivo forem bem definidas

Contras: A senha, embora não faça parte do código-fonte, normalmente é armazenado junto com ele e aumenta o risco de vazamento da senha, quando o código é disponibilizado, por exemplo, em um servidor de controle de versão ou faz parte de um projeto open source.

Adicionalmente você poderá implementar um canal seguro criptografado entre o seu servidor web e o servidor de banco de dados. O MySQL e PostgreSQL, por exemplo, aceitam realizar conexões SSL.

Com o PostgreSQL você informar o parâmetro sslmode na string de conexão do pg_connect.

$conn=pg_connect("host=10.0.0.123 port=5432 dbname=db_sample
user=foo password=bar sslmode=require");

O sslmode aceita as opções: disable, allow, prefer e require.

Já no MySQL você pode realizar uma conexão segura utilizando a flag MYSQLI_CLIENT_SSL, no método mysqli::real_connect.

$mysqli = mysqli_init();
$mysqli->real_connect('localhost', 'foo', 'bar', 'db_sample', null, MYSQLI_CLIENT_SSL);

Com esses ajustes você poderá proteger o tráfego na DMZ contra sniffing de pacotes e ataques men-in-the-middle, mas a degradação de performance é considerável quando o volume ou o número de transações for muito grande.

Conclusão

Estas são somente algumas sugestões. Tenha sempre em mente as duas premissas que apresentei no início. Você poderia implementar uma solução mais complexa onde sua aplicação armazenasse a senha  criptografa em memória e se comunicasse com um dispositivo HSM para decriptografá-la quando necessário. Pessoalmente acho um exagero, pois muitas explorações de vulnerabilidade em aplicações web não necessitam que o atacante conheça a senha de banco de dados, por exemplo, ataques de SQL/Code Injection. Chris Shiflett em 2005 já havia postado em seu blog seus dois princípios básicos de segurança. “Filter input. Escape output”

TwitterFacebookGoogle GmailOrkutDeliciousShare