IT & Engineering
Guia de segurança: como proteger sua infraestrutura contra ataques básicos
Executar sua infraestrutura em uma configuração segura é uma tarefa complexa até mesmo para profissionais de segurança. Este guia oferece conselhos práticos para ajudar a equipe de engenharia a construir uma infraestrutura seguindo práticas recomendadas de segurança, para que possa implantar seus serviços na internet pública com confiança e reduzir as chances de comprometimento. Este guia é voltado especificamente para sistemas baseados em Linux; no entanto, as práticas recomendadas se aplicam a todos os sistemas de computador.
Executar sua infraestrutura em uma configuração segura é uma tarefa complexa até mesmo para profissionais de segurança. Este guia oferece conselhos práticos para ajudar a equipe de engenharia a construir uma infraestrutura seguindo práticas recomendadas de segurança, para que possa implantar seus serviços na internet pública com confiança e reduzir as chances de comprometimento. Este guia é voltado especificamente para sistemas baseados em Linux; no entanto, as práticas recomendadas se aplicam a todos os sistemas de computador.
Parte de executar uma infraestrutura com confiança é entender contra o que e contra quem você a está protegendo. Este guia terá, futuramente, três versões (Básica, Intermediária e Avançada), com cada versão focada em defender sua infraestrutura contra um perfil de ataque diferente.
Você está lendo a versão Básica, que visa proteger contra ataques automatizados e script kiddies que entendem mais de ferramentas de exploração do que de técnicas de exploração. Esse tipo de ameaça é mais oportunista do que direcionado e passa rapidamente para alvos mais fáceis. Se você está administrando um projeto paralelo ou começando uma empresa, este é o melhor ponto de partida e ajudará a criar uma base sólida sobre a qual construir.
Ao ler este guia, considere o perfil de quem pode atacar e os tipos de ataques contra os quais você quer se defender. As práticas recomendadas que você segue ou não dependem do que está tentando defender e de contra quem está tentando se defender.
Checklist de segurança de rede
Este guia segue estes princípios norteadores em sua discussão sobre segurança de software:
- Defender, detectar e reagir. Isso significa aplicar boas práticas de segurança para defender sua infraestrutura, registrar todos os comportamentos suspeitos e, em caso de comprometimento, restaurar para um estado seguro.
- Todo software pode ser explorado. Todo software não trivial tem falhas que permitem que uma ameaça com motivação suficiente o explore.
- Simplicidade é segurança. Sistemas muito complexos se tornam mais difíceis para a equipe de desenvolvimento compreender e mais fáceis para as ameaças explorarem. Sistemas mais simples, que podem ser compreendidos logicamente, costumam ser mais seguros. Não implemente uma solução de segurança que você não entende.
- Obscuridade não é segurança. Confie na segurança dos protocolos que você usa para defender sua infraestrutura, não em portas obscuras e outros truques para tentar esconder protocolos inseguros.
- Considere todas as entradas de usuário como hostis. Considere todas as entradas aceitas de usuários como hostis e verifique rigorosamente o que você aceita.
- Princípio do menor privilégio. Forneça o privilégio mínimo necessário para que alguma operação ocorra. Se um processo ou sistema for explorado, você não vai querer permitir que o ataque obtenha mais acessos do que o minimamente necessário.
Vulnerabilidades de software
Como se proteger contra vulnerabilidades de software
Aplicar agressivamente atualizações de segurança para softwares que você não escreveu pode parecer uma maneira ruim de proteger sua infraestrutura e talvez até inútil. No entanto, é um dos melhores investimentos de tempo que você pode fazer, sob a perspectiva de segurança. Abaixo estão dois exemplos de problemas de segurança recentes que ataques pouco sofisticados usando ferramentas automatizadas podem explorar se você não atualizou seus servidores com os patches de segurança mais recentes:
- Heartbleed: permite roubar seus certificados privados e descriptografar o tráfego criptografado
- Shellshock: permite executar remotamente códigos arbitrários em seus servidores
Apenas esses dois problemas já dariam a um ataque o controle total de toda a sua infraestrutura. Felizmente, atenuar esses bugs não é difícil.
Como reduzir os danos de vulnerabilidades de software
Aplique consistentemente as atualizações de segurança fornecidas pelo fornecedor do seu sistema operacional. A maioria dos fornecedores tem um método automatizado. Por exemplo, para sistemas baseados em Debian, você pode usar o Unattended Upgrades,e para sistemas baseados em Red Hat, você pode usar o AutoUpdates.
A aplicação automatizada de patches é ótima; no entanto, ela tem uma possível desvantagem (para o seu negócio) se você não testar o seu software antes de aplicar os patches nos servidores de produção: as coisas podem quebrar inesperadamente. Por mais que quem mantém os pacotes tente garantir que as atualizações de segurança não contenham mudanças que quebrem tudo, não há como testar todas as combinações que podem estar em execução em algum lugar antes do lançamento. É por isso que é importante ter um sistema de integração contínua/implantação contínua (CI/CD) de teste (staging) ou testar manualmente as atualizações de segurança antes de implementá-las nos servidores de produção.
Apenas aplicar essas atualizações de segurança não é o suficiente, no entanto. Se o problema estiver em uma biblioteca compartilhada, você usará a versão antiga da biblioteca e ainda estará vulnerável à exploração até reiniciar o processo vinculado a ela. Para verificar se há algum binário que precisa de reinicialização, você pode usar checkrestart para sistemas baseados em Debian e needs-restarting para sistemas baseados em Red Hat.
Resumo
- FAÇA: Aplique patches em seus servidores contra as vulnerabilidades de segurança mais recentes.
- FAÇA: Use atualizações automáticas do fornecedor do seu SO sempre que possível.
- FAÇA: Reinicie todos os serviços que dependem de bibliotecas compartilhadas atualizadas.
- NÃO FAÇA: Implemente atualizações em um servidor sem executar testes.
Proteção de rede
O que é proteção de rede?
Proteger o seu aplicativo usando recursos no nível do SO é uma abordagem eficaz para limitar o escopo dos danos que podem ser causados após explorarem uma vulnerabilidade nele. Esta seção foca em usar os recursos tradicionais de controle de acesso do Unix, que a maioria dos usuários já conhece, para restringir o seu aplicativo ao conjunto mínimo de acesso necessário para operar. Os recursos são permissões em arquivos, identificador de usuário (UID) e acesso root.
O objetivo desta seção não é fortalecer seu aplicativo a ponto de impossibilitar seu comprometimento por ameaças. Esse é um objetivo quase impossível. O objetivo é limitar o que podem fazer depois que o seu aplicativo for comprometido. Após explorarem seu aplicativo, será possível realizar ações como se fosse o seu aplicativo e, possivelmente, até elevar privilégios para root, o que permite o acesso total e completo ao seu sistema operacional. O objetivo, em vez disso, é restringir as ações que seu aplicativo pode realizar ao conjunto limitado necessário para operar, o que consequentemente restringe a ameaça.
Como reduzir danos pela proteção de rede
Você quer restringir o seu aplicativo de modo que, mesmo que um processo seja explorado e um código seja executado como essa conta de usuário, o usuário tenha direitos de acesso limitados no sistema de arquivos. O mesmo conceito se aplica ao processo sob o qual a conta está sendo executada: restrinja o tempo de CPU, a memória e a contagem de descritores de arquivo para mitigar ataques do tipo DOS, nos quais seus recursos são esgotados. O objetivo é forçar a ameaça a usar um ataque de encaminhamento de privilégios (explorar outra parte do sistema operacional para elevar os privilégios além do aplicativo em execução) para fazer qualquer coisa significativa no seu sistema.
Para restringir a conta em que o seu aplicativo é executado, use as seguintes diretrizes:
- Nunca execute seu aplicativo como root ou como usuário que tenha recursos do sudo. Se o seu aplicativo for explorado, isso significa na prática que a ameaça pode obter privilégios de root.
- Se você tiver vários aplicativos, e cada um acessar dados confidenciais diferentes, considere executar cada um em sua própria conta e usar os privilégios do sistema de arquivos para isolar o acesso a dados confidenciais entre eles. Isso significa que os dados confidenciais do aplicativo nunca devem ter outras permissões configuradas que permitam acesso de leitura e gravação a qualquer pessoa. Por exemplo, nunca defina permissões para um valor como
0777; em vez disso, use um valor como0660. - Certifique-se de que tanto o usuário do aplicativo quanto o grupo tenham privilégios limitados. Isso significa criar um novo usuário limitado e um grupo para a conta e não fornecer um shell para o usuário. Suponha que você tenha um aplicativo chamado
foo. Crie um usuário chamadofooappe transforme seu diretório inicial em/var/appdata/fooapp:sudo useradd -r -s /bin/false --home /var/appdata/fooapp fooapp sudo mkdir /var/appdata/fooapp sudo chown fooapp:fooapp /var/appdata/fooapp - Transforme seu aplicativo em daemon para que ele seja iniciado automaticamente como um usuário específico. Existem duas abordagens gerais para resolver esse problema. A primeira é usar os recursos do sistema operacional (como scripts de inicialização do System V (Red Hat / Debian) ou systemd (Red Hat/ Debian) para iniciar e parar seu aplicativo e, em seguida, usar uma ferramenta de monitoramento de processos (como monit) para reiniciar seu aplicativo se ele falhar. A outra abordagem é usar um sistema de controle de processos (como supervisord, skarnet s6, daemontools) que inicializa seu aplicativo como filho e também o reinicia se houver alguma falha. Ambas as abordagens funcionam muito bem, e a escolha dependerá de qual se adequa melhor ao seu fluxo de trabalho.
Para restringir o processo que executa seu aplicativo, use as seguintes diretrizes:
- Atribua limites por processo usando o arquivo
/etc/security/limits.conf. Por exemplo, se você quiser limitar o número de descritores de arquivo abertos a 10 e limitar a memória a 1 GB, adicione as seguintes linhas ao arquivo/etc/security/limits.conf:
fooapp hard nofile 10 # limite de 10 descritores de arquivo abertos fooapp hard as 1000000 # limite de 1 GB
- Não vincule seu aplicativo a uma porta baixa. Normalmente, você deve executar seu aplicativo com privilégios administrativos para fazer isso. Em vez disso, vincule a um número de porta alto e use um proxy reverso para encaminhar suas solicitações para o seu aplicativo. Em seguida, use os recursos do Linux para permitir que seu proxy reverso se vincule a uma porta baixa sem outros privilégios. Por exemplo, se você tiver um proxy reverso em
/opt/rproxy, poderá definir seus recursos da seguinte forma:
setcap 'cap_net_bind_service=+ep' /opt/rproxy
- Por fim, considere usar
chroot, mas saiba que há certa carga extra de manutenção necessária. Ochrootpermite que você limite o escopo do que um processo pode ver no sistema de arquivos; especificamente, ele altera o diretório raiz para um diretório de sua escolha. Por exemplo, se você definir/var/chrootcomo seu novo diretório raiz, os processos verão arquivos em/var/chrootcomo/. Embora isso seja mais seguro, significa que quaisquer bibliotecas compartilhadas que o seu processo possa usar devem ser copiadas e residir em/var/chroot, o que consequentemente significa que sempre que você aplicar atualizações de segurança, precisará também copiar novamente quaisquer bibliotecas compartilhadas atualizadas. Você pode evitar essa manutenção com links físicos (hard links), mas assim oferecerá um caminho externo que pode ser explorado. Outras abordagens (baseadas em cgroup) que você pode tomar para obter benefícios parecidos serão discutidas na versão intermediária deste guia.
Resumo
- FAÇA: Crie uma conta restrita para executar seu aplicativo, o que significa não ter shell e acesso limitado ao sistema de arquivos.
- FAÇA: Vincule seu aplicativo a uma porta alta, permitindo que você o execute como um usuário sem privilégios.
- FAÇA: Use recursos em vez do root sempre que puder.
- NÃO FAÇA: Use chroot, a menos que esteja pronto para assumir o trabalho extra de manutenção.
Segurança do firewall de rede
Como revisar as regras de firewall
Regras rigorosas de firewall permitem que você defina qual comunicação de entrada e de saída é permitida em seus servidores. Começar com uma política de negação padrão e permitir apenas a entrada e saída de tráfego específico força você a pensar sobre o conjunto mínimo de serviços que deseja expor, o que, consequentemente, reduz o risco de ataques. Um processo falho não pode expor toda a sua infraestrutura ao público em geral, a menos que você permita especificamente.
Esta seção foca nas regras de firewall de entrada e nas configurações da pilha TCP/IP. Embora regras de firewall de saída sejam muito eficazes para limitar até onde um ataque pode ir depois de entrar na sua infraestrutura, a próxima versão deste guia focará nelas.
Mitigação
Primeiras regras de firewall. Ao construir um script para regras de firewall, use os seguintes princípios norteadores.
- Exclua as regras de firewall existentes. Ao desenvolver regras de firewall, você quer ter uma ideia coerente do que está bloqueando e permitindo. Descartar todas as regras existentes e começar do zero possibilita isso.
- Defina a regra padrão para o tráfego de entrada como DROP. Isso segue o princípio do menor privilégio. Após definir a política padrão como DROP, você poderá abrir lentamente sua rede, parte por parte.
- Permita o livre acesso à interface de loopback. Ao contrário das interfaces externas, vincular seu processo ao localhost costuma ser bom para a segurança e, portanto, restringir o acesso à interface de loopback causa mais danos do que benefícios. Isso deixa você com a guarda aberta a ataques de algum usuário local, mas esse é um risco que você precisa avaliar por conta própria.
- Não encerre conexões estabelecidas. Você quer evitar o encerramento da sua própria conexão SSH com um servidor e garantir que qualquer solicitação em andamento possa ser concluída antes de ser encerrada.
- Não restrinja todo o tráfego de Protocolo de Mensagem de Controle da Internet (ICMP). Permitir o ICMP é fundamental para que a internet funcione; roteadores e hosts o usam para comunicar informações importantes, como disponibilidade de serviço, tamanhos de pacote e existência de host. Os tipos 3 e 4, Destino Inalcançável (Destination Unreachable) e Extinção da Fonte (Source Quench), são essenciais, e restringi-los causará mais danos do que ganhos no futuro. Se você se preocupa em permitir que a sua rede seja mapeada por invasões, um meio-termo sensato é primeiro limitar a taxa de todo o tráfego ICMP e, depois, permitir um subconjunto restrito de tráfego ICMP em seus hosts de borda, além de permitir o acesso irrestrito para comunicação interna entre hosts.
- Aplique verificações de segurança básicas. Alguns tráfegos de entrada não têm propósito legítimo; restrinja esse tráfego. Se você sofrer ataques de um tipo específico de tráfego repetidas vezes, pode ser útil transformar isso na sua própria cadeia, caso se pegue adicionando frequentemente regras a esta seção.
- A não ser que você esteja de fato usando IPv6 e tenha como plano construir regras de firewall para tráfego IPv6, restrinja todo o tráfego IPv6 de entrada.
Abaixo está um script comentado que atinge todos esses objetivos:
Abaixo está um pequeno script para o tráfego IPv6:
Essas regras agora estão em execução na memória, e você precisa se certificar de que elas serão carregadas na próxima vez que o sistema operacional for reiniciado. Para sistemas baseados em Debian, isso significa adicionar suas regras de firewall ao /etc/network/ip-pre-up.d/ ou adicionar um comando pre-up ao /etc/network/interfaces. Para sistemas Red Hat, isso geralmente é feito usando o /sbin/service iptables comando save.
Além disso, a seguinte proteção/ajuste de pilha TCP/IP é recomendada:
- Se você estiver usando regras de firewall stateful, como no exemplo anterior, não se esqueça de aumentar o número máximo de conexões possíveis de se rastrear. Caso contrário, você pode sofrer um ataque distribuído de negação de serviço (DDoS).
- Use SYN Cookies para evitar ataques DoS do tipo SYN flood. Thomas Pornin fornece uma ótima explicação sobre o que são ataques SYN flood e como os SYN cookies mitigam esse tipo de ataque.
- Registre todos os pacotes marcianos porque é bastante provável que qualquer pacote vindo de um endereço de origem ou destino não roteável seja malicioso.
Você pode testar todas as configurações acima com o seguinte script:
Para manter essas configurações após a reinicialização, atualize o /etc/sysctl.conf:
Resumo
- FAÇA: Negue tráfego por padrão. Permita explicitamente apenas o tráfego que você sabe que deve atravessar sua rede.
- NÃO FAÇA: Restrinja unilateralmente o ICMP.
- FAÇA: Permita o livre acesso à interface de loopback.
- FAÇA: Force algumas verificações de segurança básicas.
- FAÇA: Garanta que suas regras sejam carregadas na reinicialização.
- FAÇA: Ajuste sua pilha TCP/IP para aumentar o número de conexões rastreadas e se proteger contra SYN floods.
Login remoto
Descrição
Para login remoto, é importante garantir não apenas que a comunicação com os seus servidores seja criptografada, mas também que somente usuários autorizados tenham acesso a eles. Abaixo estão os objetivos típicos ao proteger o login remoto:
- Forneça acesso limitado a usuários para que o comprometimento de uma conta de usuário não comprometa toda a sua infraestrutura.
- Criptografia forte garante que a comunicação não seja lida por invasores interceptando dados (eavesdropper).
- Não deve ser possível usar técnicas de força bruta para fazer login nos seus servidores.
- Mesmo se a sua chave for comprometida, ninguém deve conseguir obter acesso à sua infraestrutura.
- Em caso de técnicas de força bruta, a ameaça não deve conseguir esgotar os recursos do servidor.
- Somente usuários autorizados devem ter acesso aos seus servidores.
- Não deve existir nenhum login para contas administrativas de propósito geral. Todas as ações administrativas devem ser feitas por meio de alguma forma de encaminhamento de privilégios (
sudo) para registrar as ações realizadas.
A falha em cumprir qualquer um desses objetivos pode representar um risco de segurança. Uma criptografia fraca (ou nenhuma) pode permitir que ameaças visualizem sua comunicação. A autenticação fraca pode permitir que usuários não autorizados acessem os seus sistemas.
Por sorte, o Secure Shell (SSH) mitiga a maior parte desses riscos e, com alguns pequenos ajustes em seus sistemas, todos eles podem ser mitigados.
Mitigação
Para começar, gere a sua chave SSH corretamente garantindo o uso de um tamanho de chave que seja grande o suficiente e que sua chave esteja protegida por frase secreta (passphrase). Você pode fazer isso usando o ssh-keygen:
ssh-keygen -t rsa -b 4096 -C foo@example.com
Em seguida, quando solicitado, digite uma frase secreta! Uma frase secreta garante que, mesmo que alguém roube a sua chave, não consiga usá-la sem saber também a sua frase secreta.
O OpenSSH tem uma configuração padrão razoável que é bem segura. No entanto, algumas distribuições podem enfraquecer esses padrões em prol da interoperabilidade do OpenSSH com servidores legados. A configuração a seguir apenas garante que esses padrões razoáveis sejam aplicados pela sua versão do OpenSSH. Para informações mais detalhadas sobre a configuração do OpenSSH, confira O guia de configuração para OpenSSH da Mozilla e a página Proteção do SSH para o CentOS. Ambos são excelentes recursos e vamos nos basear nessas configurações nas versões futuras deste guia.
No servidor, certifique-se de ter as seguintes linhas no arquivo /etc/ssh/sshd_config:
Esta configuração atinge os seguintes objetivos:
- O Protocol 2 garante que você esteja usando uma versão segura do protocolo SSH. A versão 1 do protocolo tem vários problemas e é considerada quebrada.
PasswordAuthentication noePubkeyAuthentication yesforçam o uso de criptografia de chave pública, e não de senhas, para a autenticação em seus servidores. Apesar da possibilidade de criar uma senha forte, se ela tiver sido gerada aleatoriamente com 2048 bits de forma codificada em ASCII, mais senhas são ruins e tamanhos de senha comumente usados têm um espaço de busca muito menor do que o de uma chave grande.PermitRootLogin nodesabilita a capacidade de fazer login remotamente como usuário root. Embora isso não seja um problema diretamente explorável, desabilitar esse login remoto ajuda você a manter bons registros de auditoria para entender o que está acontecendo nos seus servidores. A conta root age como uma conta administrativa compartilhada, o que limita a sua capacidade de auditar qual usuário está realizando qual ação privilegiada. Se você forçar todos os usuários a passar por suas próprias contas, terá um rastro auditável de qual usuário executou qual ação. Detalhes sobre como configurar o registro de auditoria são fornecidos em uma seção posterior.LogLevel VERBOSEregistra o usuário e a impressão digital da chave que fez uma tentativa de autenticação. Novamente, essa configuração não mitiga diretamente uma exploração, mas é boa para auditoria.
No cliente, certifique-se de ter as seguintes linhas no arquivo /etc/ssh/ssh_config:
Esta configuração atinge os seguintes objetivos:
- O Protocol 2 garante que você esteja usando uma versão segura do protocolo SSH. A versão 1 do protocolo tem vários problemas e é considerada quebrada.
HashKnownHosts yescriptografa (hashes) nomes de host e endereços no seu arquivo~/.ssh/known_hosts. Mesmo que uma ameaça roube seu arquivo de hosts conhecidos, não poderá simplesmente enumerar os hosts aos quais você se conecta com sua chave.StrictHostKeyChecking askverifica a chave apresentada a você em relação àquela do seu arquivo~/.ssh/known_hostse, se ela tiver sido alterada (ou se for a primeira vez que você está visitando aquele host), perguntará se você aceitará a chave. Isso ajuda a mitigar ataques do tipo man-in-the-middle.
Por fim, dê aos usuários acesso limitado à sua infraestrutura. Por exemplo, nem todos os usuários precisam de acesso aos seus servidores de backup; só dê acesso aos usuários que realmente sabem como restaurar backups. Isso garante que mesmo se a conta de um usuário sem capacidade de backup for comprometida, a integridade dos seus backups não estará em risco.
Para realizar isso, duas das abordagens comuns são:
- Contas de usuário locais. Nesta abordagem, você cria contas Unix locais para seus usuários e cria as contas apenas nos servidores aos quais precisam ter acesso. Você pode usar os comandos
newuserseuserdelpara atingir esse objetivo, além de automatizar e orquestrar as ações usando ferramentas de gerenciamento de configurações como Chef ou Ansible. - Serviço de autenticação centralizado como LDAP. Com essa abordagem, os servidores aos quais cada usuário tem acesso são definidos e armazenados na configuração do servidor LDAP.
Resumo
- FAÇA: Proteja sua chave por frase secreta (passphrase).
- NÃO FAÇA: Presuma que sua distribuição tenha padrões aceitáveis. Defina estritamente o que é importante para sua infraestrutura.
- FAÇA: Use criptografia baseada em chave pública para autenticação em vez de autenticação baseada em senha.
- NÃO FAÇA: Dê a todos os usuários acesso irrestrito; determine o escopo de acesso às partes da infraestrutura que são necessárias.
Limites de confiança
Descrição
Limites de confiança são locais comuns para a ocorrência de vulnerabilidades de segurança. O limite entre o mundo exterior e a sua infraestrutura interna é sagrado, e você deve fazer o máximo possível para defendê-lo e garantir que apenas usuários autorizados consigam ultrapassá-lo.
Você deve se preocupar com dois limites de confiança principais. O primeiro é o limite entre a internet pública e o seu endpoint de API; é o limite que seus clientes cruzarão todos os dias ao usarem o seu serviço. O segundo é um ponto de acesso que será usado pela sua equipe de desenvolvimento e administração de sistema na hora de implantar e consertar o seu aplicativo.
Para o limite de confiança da API que seus clientes percorrerão, você deve considerar todas as entradas de usuário como hostis e assumir que cada solicitação feita é, na verdade, uma tentativa de explorar a sua infraestrutura. Ao pensar em solicitações de usuários dessa forma, fica claro que é preciso minimizar a superfície de ataque fornecida e isolar os danos que podem ocorrer quando alguém que usa o sistema finalmente explora o seu serviço.
Para o limite de confiança que você cruza para atender aos seus aplicativos, é bom isolar todos os seus serviços para que eles não sejam expostos à internet pública e, em seguida, forçar os usuários que os acessam a partir da internet a passarem por um ponto de acesso bem protegido que você consiga defender (vamos chamá-lo de host bastião). Você pode concentrar todos os seus recursos nesse único ponto de acesso e ter menos preocupação sobre como os seus serviços se comunicam quando estão dentro daquele limite de confiança.
Mitigação
Para mitigar esses problemas de limite de confiança, é preciso imaginar as caixas distintas nas quais você pode posicionar a internet pública e a sua infraestrutura (confira o diagrama a seguir). Depois de estabelecer isso, você poderá começar a pensar em como defender a sua infraestrutura.
A primeira caixa grande é a internet pública. Você nunca deve confiar em ninguém nem em nada na internet pública. Na verdade, é recomendável considerar todos os agentes na internet pública como hostis, mesmo quando for sua própria equipe fazendo SSH nos seus servidores.
A segunda caixa grande é a sua infraestrutura interna. Estes são os seus hosts confiáveis. Serviços executados nestes servidores devem escutar somente em interfaces de rede privada se possível, não sendo diretamente expostos à internet pública.
As duas caixas que abrangem ambos são o seu host de salto (jump host) e os seus hosts de API. Estes hosts devem ter acesso tanto à internet pública quanto à sua infraestrutura interna. Por estarem diretamente expostos à internet pública, devem ser protegidos e executar o conjunto mínimo de serviços necessários para cumprir suas tarefas.
Fortalecimento do endpoint de API
Apesar de não podermos esperar que nenhum serviço seja livre de bugs, podemos limitar o quanto uma ameaça pode explorar sua infraestrutura ao encontrar uma vulnerabilidade no serviço. É por isso que recomendamos isolar os serviços que aceitam solicitações de entrada e executá-los nos seus próprios servidores dedicados.
Você pode realizar isso dividindo as solicitações de entrada em duas partes: o balanceamento de carga e a terminação de Transport Layer Security (TLS) para solicitações de entrada, além do processamento da solicitação pelo seu próprio serviço. Ambos devem ser, no mínimo, seus próprios processos, e idealmente devem rodar em servidores diferentes, deixando o balanceamento de carga e a terminação de TLS no limite de Não confiável/Confiável. Esta seção focará no balanceamento e na terminação de carga (a proteção do aplicativo foi abordada na seção anterior).
Ao separar o balanceamento de carga e a terminação de TLS do seu aplicativo, você está limitando a possibilidade de que um bug no balanceador de carga ou no software de TLS evolua para a exploração de todo o seu aplicativo, que normalmente terá informações confidenciais carregadas na memória. Isso também fornece um ponto único de manutenção (e de falha) para aplicar patches quando uma vulnerabilidade for encontrada e você precisar fazer upgrade de sua biblioteca TLS, o que está se tornando uma tarefa cada vez mais comum.
Por exemplo, digamos que uma ameaça tenha um bug de Execução de Código Remoto (RCE) como o GHOST ou um bug de leitura de memória arbitrária (como o Heartbleed) no seu servidor HTTP ou no software de TLS. Se o seu servidor HTTP, a terminação de TLS e a lógica de aplicativo estiverem todos no mesmo processo, um bug em qualquer um deles dará à ameaça acesso a informações confidenciais das outras partes. Por exemplo, um bug no OpenSSL pode dar a uma ameaça o acesso a chaves confidenciais carregadas na memória do seu aplicativo. Da mesma forma, um bug em seu aplicativo pode dar a uma ameaça acesso aos seus certificados SSL. Porém, ao separar essas partes, se uma for explorada, a outra não será, e a perda se restringirá a apenas alguns dados confidenciais.
Para o balanceamento de carga, escolhas comuns são NGINX, HAProxy, e Apache. A terminação TLS geralmente é feita com o OpenSSL; no entanto, alternativas como o LibreSSL e Mozilla NSS também existem. Outra alternativa é usar algo como o vulcand, que atua como balanceador de carga e usa a biblioteca TLS Go para terminação TLS.
Fortalecimento do endpoint de serviço (e todo o resto)
É possível fortalecer o seu endpoint de serviço restringindo o acesso aos seus servidores partindo da internet pública e forçando todas as autenticações a passarem por um jump host. Essa restrição geralmente é obtida sem expor diretamente a sua infraestrutura à internet pública e, no lugar disso, construindo algum tipo de rede interna que só pode ser acessada por meio do host bastião.
Há muitas formas de construir uma rede interna, e sua abordagem dependerá bastante de como sua infraestrutura está configurada pelo seu provedor de serviços e também das suas preferências.
Por exemplo, imagine que você hospede seus servidores na Amazon Web Services (AWS). Então você pode começar com uma Virtual Private Cloud (VPC) com uma única sub-rede pública. Seus servidores ficarão isolados de outros servidores na AWS e residirão em seu próprio bloco CIDR 10.0.0.0/16. No entanto, eles ainda terão acesso irrestrito à internet. Para restringir o acesso partindo da internet, crie Grupos de segurançaque restrinjam tanto as portas que ficam abertas quanto os servidores que podem acessá-las. Por exemplo, você configuraria seus worker hosts para aceitarem conexões nas portas 22 e 80, mas apenas do seu jump host e balanceador de carga, respectivamente. Seu servidor de salto, no entanto, aceitaria conexões na porta 22 de qualquer servidor na internet pública.
Se o seu provedor de serviços não fornece essas ferramentas, é possível alcançar os mesmos resultados desde que haja suporte a algum tipo de rede privada, seja compartilhada ou dedicada, que possibilite isolar o tráfego público e o privado. Esse recurso normalmente é oferecido pela maioria dos fornecedores: como mencionado antes, a Amazon o chama de VPC, a Rackspace o chama de ServiceNet, e a Digital Ocean o chama de Private Networking. Todas oferecem basicamente a mesma capacidade: ao construir o seu servidor virtual, você pode vinculá-lo à interface pública, à interface privada, ou a ambas. Se o seu provedor de serviços não tiver essa capacidade no momento da criação, você poderá habilitar e desabilitar essas interfaces por conta própria no arquivo /etc/network/interfaces em um sistema baseado em Debian e no arquivo /etc/sysconfig/network-scripts/ifcfg* em um sistema baseado em Red Hat.
Quando tiver servidores com interfaces públicas e privadas, use o iptables para restringir o tráfego de entrada em interfaces publicamente acessíveis aos servidores que atuam como jump hosts ou executam a API acessível de forma pública. Os servidores que lidam com todos os serviços internos, como o seu aplicativo e o servidor de banco de dados, não permitem qualquer tráfego de entrada em interfaces públicas e restringem o tráfego de entrada nas interfaces privadas ao conjunto de servidores confiáveis.
Depois que você alcançar isso, a única maneira de ameaças explorarem a sua infraestrutura usando a internet pública será por meio do host bastião protegido ou explorando sua API de alguma maneira.
Por fim, para acessar esses servidores, não use o ssh-agent; em vez disso, use o ProxyCommand. Apesar de o ssh-agent ter suas utilidades, ele não é bom para este caso de uso específico. Se o usasse, qualquer pessoa que tivesse uma exploração local de encaminhamento de privilégios para o seu servidor bastião poderia acessar qualquer servidor na sua infraestrutura fingindo ser qualquer um que tivesse chaves carregadas na memória pelo ssh-agent. Em contrapartida, com o ProxyCommand, suas chaves não ficarão na memória para que alguém as roube e sua chave privada ficará exclusivamente na sua estação de trabalho local; apenas a sua chave pública será copiada para cada servidor ao qual você precisa de acesso.
Para usar o ProxyCommand, copie sua chave pública para ~/.ssh/authorized_hosts em todos os servidores aos quais precisa de acesso. Em seguida, em sua estação de trabalho, atualize seu arquivo ~/.ssh/config com as seguintes informações:
Essa configuração permite acessar os servidores server1.example.com e server2.example.com a partir de workstation.example.com via SSH nas interfaces privadas deles “saltando” através de jump.example.com, que tem acesso tanto à interface pública quanto à privada. Tudo o que você precisa fazer para se conectar é digitar ssh server1.example.com ou ssh server2.example.com.
Resumo
- FAÇA: Use um balanceador de carga para separar o servidor HTTP de aplicativo do servidor HTTP voltado para o público.
- FAÇA: Faça a terminação do TLS no balanceador de carga.
- FAÇA: Use um jump host protegido para controlar o acesso à sua infraestrutura.
- NÃO FAÇA: Use agente SSH se puder evitar. Ele deixa todas as suas chaves possivelmente expostas se alguém tiver uma exploração local de encaminhamento de privilégios.
- FAÇA: Use as interfaces públicas e privadas que o seu provedor disponibiliza para isolar seus serviços internos da internet pública.
Monitoramento e registro
Descrição
Toda medida de segurança pode e será burlada em algum momento. Como não existem medidas de segurança práticas que ofereçam garantias infalíveis, é importante ter mecanismos robustos de monitoramento e de registros (logging) que ajudem a entender onde e como os seus sistemas foram comprometidos. Quanto mais você entende como e o que está sendo executado em seus sistemas, melhor será a detecção de comportamentos anômalos. Da mesma forma que um banco instala câmeras de segurança mesmo com cofres protegidos, ter boas ferramentas de monitoramento é fundamental para pegar cibercriminosos espertos que tenham superado as suas medidas de segurança.
Monitoramento e registros ocorrem de duas formas. A primeira é o monitoramento ao vivo, que permite a você ver o que está acontecendo no seu sistema a qualquer momento. Isso engloba tudo, desde os soquetes de rede que estão abertos até os processos que estão em execução no momento. A segunda diz respeito aos dados de registro de ações que já foram realizadas. Isso abrange tudo, desde o registro da lógica de aplicativos até os registros do sistema.
Nesta seção, falaremos sobre a visualização de registros do sistema nos próprios servidores individuais. Na versão intermediária deste guia, abordaremos o tema de agregação e alertas de registros.
Mitigação
As ferramentas a seguir vêm incluídas na maioria dos sistemas operacionais baseados em UNIX. Elas são úteis de se usar quando você suspeita de que um incidente de segurança está ocorrendo, mas também são fundamentais de se usar com antecedência, para que você entenda as saídas normais de cada uma.
Monitoramento ao vivo
Abaixo há alguns comandos e suas saídas esperadas em condições normais de operação. Esses exemplos ilustram como deve ser a saída no s
who – Mostra quem está conectado no momento.
last -a – Mostra uma lista dos últimos usuários conectados. Imprime o nome de usuário, a hora de conexão, bem como os endereços IP a partir dos quais os acessos foram feitos.
netstat -plntu – Mostra os nomes dos processos e as portas em que estão escutando conexões.
netstat -ap – Mostra um fluxo ao vivo de todas as conexões, incluindo conexões de saída estabelecidas.
find / -mtime -1 -ls | head -n 20 – Lista os 20 principais arquivos modificados nas últimas 24 horas.
faillog -a para ver um resumo de falhas de login. Isto também é útil para limitar o número máximo de logins com falha de um usuário.
tcpdump -i eth1 -s 0 -A tcp port http – Despeja todo o tráfego HTTP na interface eth1. Isso é útil caso você tenha encontrado algo suspeito ao usar o netstat e deseje ir mais a fundo. Este guia não pode apresentar a você todos os detalhes do tcpdump, mas há uma variedade de recursos na internet para ajudar você a entender o tcpdump.
Monitoramento de registros
Abaixo estão algumas regras gerais para lidar com registros (logging) de aplicativos e ponteiros para registros importantes do sistema.
Registros gerais de aplicativos
Agregue seus registros de aplicativo em um local central, seja um único arquivo de registro ou um diretório. A abordagem mais comum para isso é usar o syslog para essa finalidade. O uso do syslog facilitará no futuro o envio dos registros para um servidor central de registros.
Mantenha seus registros enquanto o espaço em disco permitir. Manter os registros por até 90 dias no disco não é irrazoável se você tiver espaço para isso.
Registros de sistema
Assim como no monitoramento ao vivo, é uma boa ideia acompanhar os seguintes arquivos de registro do sistema de forma contínua para desenvolver uma boa base de saída esperada. Ter uma base torna a detecção de comportamentos suspeitos muito mais fácil no futuro. Abaixo está uma lista parcial de registros de sistema interessantes para se observar:
/var/log/auth.log– Registros de autenticação do sistema./var/log/syslog– Se você não estiver enviando registros para um recurso syslog específico, eles serão colocados aqui./var/log/messages– Mensagens gerais de registro do sistema.~/.bash_history– Lista de comandos Bash que foram executados pelo usuário. Este registro pode ser manipulado ou apagado facilmente em ataques sofisticados./var/log/utmpe/var/log/wtmp– Estes registros contêm os usuários conectados no momento e o histórico de todos os usuários já conectados. Uselast -fpara visualizar estes arquivos.
Resumo
- Aprenda alguns comandos básicos que podem ajudar você a descobrir o que está acontecendo nos seus servidores no momento. Estes comandos incluem
who,last,lsof,netstat,faillogefind. - Descubra o que você precisa registrar. Os registros não têm utilidade se não capturarem eventos críticos de segurança. No mínimo, monitore os seguintes arquivos:
/var/log/auth.log,/var/log/sysloge/var/log/messages. - Comece a centralizar os seus registros o mais cedo possível. Usar o syslog agora, em vez de alguma estrutura de registro personalizada, facilitará o envio dos registros para um servidor de registros centralizado no futuro.
Uso de criptografia
Descrição
A criptografia é um tópico complexo que deveria ser abordado de forma separada. Mesmo os mais leves descuidos ou erros podem levar ao comprometimento completo da segurança de um produto. É por isso que o mantra “não invente sua própria criptografia” (don’t roll your own cryptography) é tão repetido. Duas boas fontes de leitura antes de você começar a trabalhar com criptografia são o Crypto101 escrito por Laurens Van Houtven (lvh) e os desafios de criptografia da Matasano.
Dito isto, manter sua infraestrutura segura requer algum uso de criptografia, e existem padrões comuns que podem ser usados com segurança. Esta seção abrange um desses padrões: como armazenar dados confidenciais no código-fonte (ou no disco).
Mitigação
Ao armazenar credenciais, seja no controle de código-fonte ou no disco, não as armazene sem criptografia. Você pode pensar que as suas senhas estão seguras usando um repositório privado do GitHub, mas não é bom depender apenas do GitHub para manter toda a sua infraestrutura segura contra ataques. Criptografando suas credenciais, é possível manter a segurança mesmo se o GitHub for comprometido.
Ao procurar uma ferramenta ou biblioteca para criptografar pequenas quantidades de dados, considere as seguintes recomendações:
- Use uma cifra simétrica moderna. Dois candidatos comumente sugeridos são AES e Salsa20 (NaCl).
- Se a sua cifra simétrica oferecer suporte a modos diferentes, selecione o modo com cuidado. Por exemplo, CBC é um bom modo para se usar com AES, ao passo que ECB não é.
- Use um Código de Autenticação de Mensagem (MAC) para garantir que os dados criptografados não sofreram adulteração. HMAC-SHA-512 ou Poly1305 são bons candidatos.
- Use uma fonte de aleatoriedade de alta qualidade, o que normalmente significa usar
/dev/urandompara obter números aleatórios usados em chaves, salts e nonces. - Se a biblioteca ou ferramenta funcionar com frases secretas (passphrases), garanta que ela usa uma KDF para transformar a frase em uma chave.
Você pode construir uma ferramenta de criptografia por conta própria, mas como mencionado, isso pode ser complicado e não é o recomendado. Entretanto, se insistir em construí-la, use uma biblioteca como NaCl ou cryptography.io para que ao menos você acerte na criptografia. No entanto, é ainda melhor usar uma “receita” que alguém já construiu para isso, como o lemma ou Fernet ambos expõem uma API simples que pode ser usada para criptografar e descriptografar dados de maneira segura.
Resumo
- NÃO FAÇA: Escolha aleatoriamente o modo da cifra simétrica.
- FAÇA: Use uma cifra simétrica autenticada com um MAC.
- FAÇA: Use
/dev/urandompara gerar material aleatório. - FAÇA: Use uma “receita” pronta se você puder.
Backups
Descrição
Embora backups possam não parecer pertencer à mesma categoria dos outros tópicos discutidos neste guia, eles importam igualmente para a segurança da infraestrutura. Os backups têm dois propósitos principais: a restauração no caso de alguma falha de hardware não maliciosa e no caso de a infraestrutura ser comprometida por um ataque. Lembre-se, em caso de comprometimento, é melhor apagar o seu servidor e criar um novo do que tentar remover o malware, o que pode ser uma tarefa difícil ou até impossível para iniciantes. É por isso que os backups são cruciais no caso de um comprometimento para trazer sua infraestrutura de volta a um estado confiável.
Mitigação
As seguintes abordagens são uma boa estratégia geral a ser seguida ao trabalhar com backups:
- Não deixe de proteger seus backups só porque não parecem ser essenciais para a missão do seu serviço. Ameaças comumente focam em infraestrutura de backup justamente por esse motivo.
- Faça backups com a frequência adequada para as necessidades do seu negócio. Uma vez por dia é razoável.
- Seus servidores de backup devem ter acesso limitado, e as contas existentes devem usar mecanismos de autenticação e autorização diferentes daqueles usados no restante da sua infraestrutura. Por exemplo, seus servidores de backup devem usar uma chave SSH diferente para fazer o login. Se você fizer essas coisas e seu ambiente principal for comprometido, ainda terá backups confiáveis dos quais poderá restaurar.
- Se não quiser executar sua própria infraestrutura de backup, faça backup em um repositório de dados terceirizado como o Amazon S3. Vale notar que se for usar qualquer serviço de terceiros, você deverá criptografar seus backups antes de enviar os dados a eles. Trabalhe com a presunção de que o seu repositório de dados é público e use a criptografia para proteger os seus dados. Se você trabalhar com essa mentalidade, mesmo que seu host seja comprometido, seus dados estarão seguros.
- Se estiver usando o Amazon S3 ou Rackspace CloudFiles, use uma receita de cifra autenticada como lemma ou Fernet. Se não quiser se preocupar com a criptografia, use um serviço que criptografe seus dados no cliente e envie apenas blobs criptografados para o serviço dele, como o Tarsnap.
- Faça o backup de seus repositórios de código-fonte, de qualquer software de terceiros usado pelo seu aplicativo e do seu banco de dados. O recente exemplo da FoundationDB ilustra a importância de fazer o backup de todo software que você usa. Os downloads de software podem ser revogados por quem os desenvolve a qualquer momento e por qualquer motivo.
- Embora os sistemas de controle de versão distribuídos (DVCSs) como o Git forneçam alguma redundância, eles não substituem backups reais. Você não vai querer depender de uma ramificação específica na estação de trabalho de colegas para garantir a continuidade dos negócios.
- Faça o backup do banco de dados usando o método que ele prescreve.
- Restaure partindo dos backups com a mesma frequência com que executa os próprios backups. Os backups não terão nenhuma utilidade se não forem usáveis. No cenário ideal, você poderá executar alguns serviços auxiliares que não requeiram os dados mais recentes de acordo com seus backups restaurados. Dessa forma, se algo der errado, você saberá imediatamente.
- Garanta que várias pessoas da sua equipe consigam restaurar a partir dos backups. Você pode ser capaz de descobrir como restaurar seus backups, ou talvez não. Isso pode levar uma hora ou dez horas. É melhor passar algumas horas a cada trimestre revisando a infraestrutura de backup com um colega de trabalho.
Resumo
- NÃO FAÇA: Use as mesmas contas de seu ambiente principal para backups.
- FAÇA: Realize backup de repositórios de origem, de softwares de terceiros e de bancos de dados.
- FAÇA: Tente fazer a restauração de backups com a mesma frequência com que você executa o procedimento de backup.
- FAÇA: Execute serviços auxiliares baseados em backups restaurados, se puder.
- NÃO FAÇA: Tenha um ponto único de falha. Tenha várias pessoas na sua equipe que consigam fazer a restauração de backups.
- FAÇA: Criptografe seus backups com uma cifra autenticada. Use uma ferramenta como lemma ou Fernet, ou uma solução hospedada como o Tarsnap.