Segurança é um tema que só quem tem experiência se preocupa. Neste caso, experiência significa que você já foi invadido um dia. E a pergunta nunca é se você será invadido, mas quando. Um cliente me pediu um resumo rápido das medidas de segurança para proteger o seu PostgreSQL. Comecei a enumerar e achei melhor escrever aqui, uma vez que é um assunto que está tirando o sono de muita gente.
RTFM
Saiba o que está fazendo, leia a documentação oficial e não apenas em blogs e vídeos no YouTube! Veja se a documentação que você está lendo se refere a versão correta do software que você está utilizando.
Proteja o seu servidor
Instalação do servidor: menos é mais
Instale somente o necessário. Crie um servidor dedicado apenas com o essencial. Tudo que não for absolutamente necessário deve ser removido. Isso inclui serviços de compartilhamento de arquivos, impressão e até a interface gráfica… mesmo que o seu servidor seja em Windows. Além de economizar um pouco de espaço em disco, economizar CPU e memória você abre um número menor de portas no seu servidor e tem menos softwares com possíveis falhas de segurança instalados.
Mantenha as atualizações de segurança em dia
Prefira sempre instalar o PostgreSQL empacotado ao invés de compilado. Se estiver utilizando uma distribuição Linux, use o repositório do PGDG. Se for uma distribuição que usa pacotes RPM, utilize o repositório YUM do PGDG, se for uma distribuição que utiliza pacotes DEB utilize o repositório APT do PGDG. Feito isso, faça atualizações de segurança do seu sistema operacional com frequência. Muitas invasões exploram falhas de segurança conhecidas e já corrigidas. Mas você precisa atualizar o seu Sistema Operacional (incluindo o PostgreSQL), senão o trabalho dos desenvolvedores para corrigir as falhas de segurança não adiantam nada.
Limite o acesso físico
Cuide do acesso físico ao servidor. Onde seu servidor fica? Lembre-se que qualquer pessoa que tenha acesso físico ao servidor pode para começar tirar ele da tomada… e pode até ser sem querer. Com um pouco de conhecimento a pessoa pode dar um boot num pen drive com um Linux qualquer e ter acesso TOTAL ao seu servidor e fazer o que ele quiser. Portanto, guarde seu servidor em um local seguro. E por mais que você tenha gastado muito dinheiro para compra-lo, não coloque ele numa vitrine para todos contemplarem ele. Servidores devem ficar numa sala escondida onde apenas quem precisa sabe onde fica e pode entrar lá. Trabalhei por anos na Itautec ao lado do CTO do Itaú. Ia jantar lá toda semana e nunca soube em que andar ficam os servidores.
Limite o acesso privilegiado remoto
Algumas pessoas provavelmente terão acesso remoto ao servidor. A primeira coisa a fazer é limitar o número de pessoas que vão ter acesso. Quem realmente precisa ter acesso à ele? A segunda é criar usuários únicos para cada uma delas no SO e dar uma senha diferente para cada uma delas. Rastreie a conexão das pessoas no servidor. Se cada um tiver um usuário diferente, você saberá quem se conectou quando. Não confie apenas em senhas para o acesso. Exija que os usuários tenham certificados para poder acessar o servidor.
Utilize conexões encriptadas com SSL
Se toda a informação da sua conexão trafegar pela rede pública sem encriptação…. toda a sua preocupação com segurança vai por água a baixo. Então se os seus dados não trafegam numa rede segura e isolada, configure no servidor e clientes para minimizar a chance ter seus dados roubados inadvertidamente, inclusive senhas. Veja na documentação como fazer isso e teste com calma antes de ativar conexões hostssl no pg_hba.conf
Proteja o IP do servidor
Seu servidor jamais deve ter um IP válido na Internet. Isso é um erro imperdoável. Para chegar ao servidor você deve primeiro acessar um servidor intermediário, através de um Firewall e ou uma VPN. Jamais deixe seu servidor exposto numa rede pública. O resultado é fatal.
Limite o acesso das aplicações
O PostgreSQL possui um mecanismo sofisticado e simples para filtrar as conexões antes de chegarem ao seu banco de dados. Ele se chama pg_hba.conf e possui um capítulo específico na documentação só sobre ele. LEIA. Se você utiliza alguns poucos servidores de aplicação, então você deve limitar o acesso a estes IPs específicos individualmente. Se você tem uma aplicação client/server, limite o acesso a uma faixa de IPs. Jamais libere tudo. Limite também qual usuário ou grupo pode utilizar qual base. Você pode utilizar também as opções sameuser se tiver uma base para cada cliente por exemplo. Se você tem uma aplicação client/server, pode optar também por utilizar uma autenticação via LDAP.
Cuide das suas senhas
Cuidar de senhas é uma baita dor de cabeça. O PostgreSQL oferece algumas ferramentas para te ajudar:
- Senhas fáceis são um problema contra ataques de força bruta. O PostgreSQL possui o módulo do contrib chamado auth_delay para te ajudar a criar um atraso na autenticação, dificultando bastante ataques de força bruta. Não é algo muito elegante mas pode te ajudar se perceber que está sofrendo ataques desse tipo.
- Outro módulo mais elegante é o uso do módulo passwordcheck. Este faz uma checagem automática toda vez que você criar um usuário com senha ou tentar alterar a senha. Se a senha for considerada fraca o comando dá erro e rejeita a senha. Ele tem um algorítimo próprio para definir as regras sobre o que é uma senha ruim. Você pode alterar o código fonte para mudar as regras se quiser.
- Utilize outro método de autenticação que não MD5 ou SHA (o SCRAM-SHA-256 for introduzido no PostgreSQL a partir da versão 10). O PostgreSQL fornece varias alternativas como
- GSSAPI
- SSPI
- Ident / Peer
- LDAP
- RADIU
- Certificado SS
Privilégios: menos é mais
Você deve criar usuários separados para as suas aplicações e limitar o seu acesso:
- Jamais, em hipótese alguma utilize um superusuário para a aplicação se conectar no banco de dados. Se alguém conseguir acesso ao banco de dados com um superusuário ele vai poder fazer qualquer coisa. E qualquer coisa não é algo nada divertido aqui.
- Um usuário deve ser o dono dos seus objetos. Você vai utilizar este usuário apenas para o deploy. A aplicação jamais deve utilizar este usuário. O dono (owner) dos objetos pode criar e destruir qualquer objeto no banco de dados, logo, por uma questão de segurança, deve ficar protegido e longe da aplicação.
- Se o usuário deve utilizar uma senha para entrar na aplicação e ele tiver uma senha no banco de dados, lembre-se que a senha do banco de dados não pode ser a mesma da aplicação. A coisa mais fácil que existe é o seu usuário instalar um client (pode até ser numa planilha via ODBC) e acessar diretamente o seu banco de dados com o usuário e senha dele. Adivinha o que pode acontecer se o seu usuário sair fazendo UPDATE e DELETE diretamente nas tabelas do sistema? Adicione um sufixo e um prefixo para o nome do usuário no banco de dados, faça a mesma coisa com a senha e depois embaralhe ela com um MD5 ou um SHA, depois crie o usuário no banco de dados. Quando for autenticar o usuário refaça a mesma operação todas as vezes. Não é um método muito seguro, mas ajuda a tirar os usuários comuns mal intencionados (como um funcionário comum que quer pedir demissão) de fazer um estrago.
- Se todos os usuários da aplicação utilizam o mesmo usuário do banco de dados ou um pequeno grupo de usuários no banco de dados, você vai ter que guardar a senha deste usuário em algum lugar na máquina onde está a aplicação. Jamais guarde isso em um arquivo texto puro. Qualquer um que tiver acesso à máquina vai poder abrir este arquivo e fazer a festa no seu banco de dados. Você pode encriptar um arquivo com uma chave guardada dentro da aplicação. Também pode utilizar outros métodos de autenticação sem senha, utilizando certificados.
- Como os usuários da aplicação no banco de dados não são donos dos objetos, você vai ter que conceder privilégios em cada tabela/função/visão/sequencia, etc individualmente. Antes de mais nada, dê uma olhada na documentação para aprender como isso funciona direito. Ajustar isso é um trabalho chato e tedioso. Ninguém gosta de fazer isso, mas precisa ser feito. E precisa ser feito no ambiente de desenvolvimento e homologação também. É terrível quando você faz um deploy na produção e a aplicação para de funcionar por falta de um simples GRANT. Isso acontece quando os testes foram feitos com um usuário com mais privilégios que o da produção. Tente dar apenas os privilégios extremamente necessários para cada usuário ou grupo de usuários (role). Se você nunca apaga registros de uma tabela, não dê um GRANT de DELETE nela. Fazer este ajuste fino em cada tabela pode levar muito tempo. As pessoas tendem a dar GRANT em tudo e apertar com bastante força o “botão do FODA-SE”! Resista a tentação. Se você tem centenas ou milhares de objetos para dar GRANT e não tem condições de revisar toda a sua aplicação para isso, revise pelo menos o acesso aos objetos mais sensíveis. A regra nesse caso é: “o cofre não pode ser mais caro que o ouro”. Então avalie o custo de acertar todos os privilégios um por um e avalie o custo de alguém apagar todos os dados em uma tabela com dados críticos.
- Se você tem uma tabela com dados realmente importantes, você não deveria deixar a sua aplicação fazer SELECT, UPDATE, DELETE diretamente. Ao invés disso, crie visões (views) e funções que filtrem o acesso aos dados para você a sua aplicação. Assim você impede um UPDATE sem WHERE por exemplo ou o acesso à todas as linhas de uma tabela que tem restrições de privacidade.
- Se você armazena dados realmente sensíveis como números de cartão de crédito (tenho medo de quem armazena esse tipo de coisa…) você deve encriptar as informações nestas colunas. O PostgreSQL tem um módulo do contrib chamado pgcrypto que faz isso. Não é algo trivial de se utilizar. Precisa gastar um tempo para entender como fazer isso. Mas é praticamente a única opção se você realmente precisa armazenar dados assim. Nem o seu DBA deve poder ver as informações nessas colunas!
- Se você tem restrições severas a quais linhas de uma tabela o seu usuário pode acessar você pode utilizar o políticas de acesso em nível de linha. Não é algo tão complexo mas exige um pouco de planejamento para utilizar. A documentação tem alguns exemplos simples para lhe dar uma ideia de como funciona na prática.
Proteja a sua aplicação
O lado da aplicação é um lado frágil da corrente em termos de segurança. Você não pode evitar por exemplo que um servidor web fique exposto à uma rede pública como já fez com o banco de dados. Como está mais vulnerável você deve tomar uma serie de medidas para limitar o estrago o servidor onde a aplicação está seja comprometido. Então além de praticamente adotar os mesmos cuidados que utilizou no seu servidor de banco de dados, o lado da aplicação deve tomar cuidados adicionais.
Trilhas de auditoria
Uma forma importante de auditar quem mexeu no meu queijo e ter trilhas de auditoria em tabelas específicas. Saber quem alterou o que e quando é fácil e existem várias extensões prontas para fazer isso. Ou você também pode criar um gatilho para alimentar uma tabela de auditoria. Claro que você tem que proteger a tabela com os dados de auditoria e não dar GRANT para nenhum usuário dar DELETE ou UPDATE nela. Se o usuário da aplicação for o dono da tabela de auditoria então… melhor nem fazer.
SQL Injection
Este é um mal que afeta aplicações descuidadas, principalmente aquelas expostas na interntet. Existem zilhões de receitas prontas para invadir bancos de dados utilizando SQL Injection. E por incrível que pareça, as pessoas continuam caindo nisso! O assunto é um pouco extenso, mas tenho um artigo escrito especificamente sobre isso aqui. Veja que neste tipo de ataque, você não precisa explorar nenhuma vulnerabilidade do servidor, nem ter qualquer tipo de senha. O único elo frágil aqui é a sua aplicação. Então ou você aprende a escrever aplicações blindadas contra SQL Injection, ou você será invadido. Certeza.
Gere logs
Logs podem lhe ajudar a entender o que está acontecendo quando as coisas dão errado. Você pode sofrer uma invasão, perder dados e ser invadido novamente depois por não ter se protegido adequadamente. A única forma de entender o que aconteceu é gerar log no SO, na aplicação e no banco de dados. Gere logs sempre e aprenda a analisa-los de forma eficiente. Hoje temos uma infinidade de ferramentas para ajudar nisso. JUST DO IT!
Se tudo o mais falhar: backup
Parece besteira, mas muita gente não tem a menor ideia de como fazer um backup direito num banco de dados e tem aplicações enormes rodando em produção sem jamais terem lido a documentação sobre isso. Só um detalhe importante: ter um standby não lhe protege contra perda de dados em caso de invasão. Se o invasor apagar os dados de uma tabela em produção, esta alteração vai ser propagada para o standby. Portanto, você NÃO PODE FICAR SEM BACKUP. E como eu já escrevi e repeti por aqui… Dump não é backup!!!