Skip to main content

Protegendo contêineres PHP

Escrito por
Headshot of Neema Muganga

Neema Muganga

feature safe containers

4 de agosto de 2022

0 minutos de leitura

Segundo o Wappalyzer, o PHP está presente em mais de doze milhões de sites. Nada mal para uma linguagem de 28 anos! Apesar da idade, o PHP acompanhou as práticas modernas de desenvolvimento. Com suporte a declarações de tipo e frameworks excelentes, como Laravel e Symfony, o PHP continua sendo uma ótima opção para desenvolver aplicações web. 

O PHP funciona bem em ambientes conteinerizados. Com uma imagem oficial disponível no Docker Hub, os desenvolvedores sabem que podem contar com imagens de contêiner PHP bem testadas para usar como base.

Ainda assim, é preciso ter cuidado ao criar imagens de contêiner para aplicações PHP. Como o PHP é tão difundido e amplamente usado, as aplicações PHP são um alvo grande e atraente para invasores. Além disso, como trabalhamos com contêineres e microsserviços, é provável que usemos contêineres PHP junto com aplicações de terceiros, o que cria outro caminho para a exploração de vulnerabilidades.

Com frequência, desenvolvedores presumem que o isolamento de contêineres significa que eles são seguros por natureza. Essa suposição equivocada leva à complacência. Ter atenção à segurança continua sendo essencial, mas, com um pouco de cuidado e dedicação, desenvolver e executar aplicações PHP conteinerizadas com segurança não é difícil.

Com isso em mente, vamos explorar na prática algumas práticas recomendadas para proteger contêineres PHP.

Pré-requisitos

Para aplicar essas práticas recomendadas e acompanhar esta demonstração, tenha as seguintes ferramentas:

  • Docker instalado na sua máquina. Vamos usar o Docker para executar nossos contêineres PHP e aproveitar os recursos integrados do Docker para protegê-los.

  • Uma conta gratuita da Snyk. Vamos usar as ferramentas de análise de segurança da Snyk para identificar — e corrigir — vulnerabilidades nos nossos contêineres.

  • Node.js para instalar e executar a Snyk CLI, ou consulte a documentação de instalação da Snyk CLI para conhecer outros métodos.

Práticas recomendadas para contêineres

Os contêineres são uma forma prática de executar aplicações PHP. Embora ambientes de execução de contêineres, como o Docker, isolem os contêineres uns dos outros e do sistema operacional host, esse isolamento não é perfeito e já foi contornado no passado.

No entanto, você pode tomar várias medidas para tornar seus contêineres PHP mais seguros, incluindo as seguintes.

Defina limites de recursos e use cotas

A configuração de cotas de recursos por contêiner limita a quantidade de recursos do sistema que ele usa. Esses recursos incluem a memória e a CPU consumidas pelo contêiner, além da largura de banda de E/S do disco. Desenvolvedores PHP podem usar várias opções do ambiente de execução de contêineres para limitar o acesso do contêiner a esses recursos.

CPUs

A flag –-cpus <value> define o número de CPUs que o contêiner pode usar. Por exemplo, quando definimos --cpus 3.5, permitimos que o contêiner use exatamente três CPUs e meia, ou núcleos de CPU.

Se você precisa de um controle mais granular, consulte a documentação das flags cpu-quota e cpu-period do Docker. Mas lembre-se: para usar essas flags com eficácia, é preciso entender os períodos do escalonador do Linux.

Veja um exemplo de como executar um contêiner PHP com limites de uso de CPU:

$ docker run -it --cpus 3.5 php:7.4-cli /bin/bash

Memória

A flag -m ou –memory= define a memória máxima disponível para o contêiner. Podemos usar um número inteiro positivo seguido de b, k, m ou g para especificar bytes, quilobytes, megabytes ou gigabytes, respectivamente.

Por exemplo, com o comando abaixo, vamos limitar a reserva de memória do contêiner a 800 MB e definir a RAM máxima em 1,5 gigabyte.

$ docker run -it --memory 1.5g --memory-reservation 800m php:7.4-cli /bin/bash

Limitar os recursos disponíveis para um contêiner reduz o impacto potencial de um ataque, pois diminui a chance de ele consumir tantos recursos a ponto de interferir no funcionamento do sistema operacional host ou de outros contêineres. Essa abordagem aumenta a segurança de cada contêiner e reforça a segurança geral do ambiente host.

Sem cotas, os contêineres deixam o sistema vulnerável a ataques de negação de serviço (DoS). Um ataque DoS pode interromper os serviços em execução no sistema, prejudicando a experiência dos usuários. Isso mostra como contêineres sem cotas podem se tornar um risco de segurança para a empresa se não forem gerenciados adequadamente.

Se você executa contêineres PHP com Kubernetes em vez de Docker, entender as configurações de contexto do Kubernetes é essencial para manter a segurança dos contêineres.

Evite executar contêineres como root

O ideal é evitar executar nossos contêineres como usuário root ou com uma conta que tenha mais privilégios do que o necessário. Em vez disso, devemos sempre seguir o princípio do menor privilégio ao criar contas de usuário para nossos contêineres.

A maioria dos ambientes de execução de contêineres oferece maneiras de executá-los com uma conta que não seja root. O Docker oferece um modo rootless para executar o ambiente de execução e todos os seus contêineres com uma conta de usuário comum.

O Kubernetes também oferece várias opções para executar nós e contêineres sem root. De forma mais ampla, qualquer ambiente de execução de contêineres compatível com OCI permite especificar exatamente qual usuário e grupo devem ser usados por meio das propriedades UID e GID no nosso arquivo de configuração do ambiente de execução.

Quem usa a Snyk para analisar arquivos de configuração do Kubernetes ou arquivos IaC do Terraform também pode identificar as configurações incorretas mencionadas acima, como Limites de memória não definidos ou Contêiner executado como root. A Snyk destaca esses problemas visualmente e indica as linhas do arquivo YAML que não seguem essas práticas recomendadas de segurança:

A análise de segurança aponta problemas em contêineres do Kubernetes, enquanto um YAML de Deployment destaca o compartilhamento do PID do host, a ausência de limites de memória e configurações privilegiadas.

Tomando o Docker como exemplo, executar nossos contêineres PHP no modo rootless não é muito diferente de quando o Docker é executado como root. Todos os comandos habituais do Docker devem funcionar, mas lembre-se de que os privilégios que podemos conceder a um contêiner serão limitados aos privilégios da conta de usuário que executa o daemon do Docker. Há um detalhe: se você já instalou o daemon do Docker com a configuração padrão, precisará desinstalá-lo e reinstalá-lo no modo rootless, seguindo as instruções da documentação do Docker.

Evite usar um usuário root dentro dos contêineres

Além de executar contêineres no modo rootless, devemos evitar usar um usuário root dentro deles. Embora isso possa parecer redundante se já executamos o contêiner no modo rootless, é uma camada adicional de defesa contra usuários mal-intencionados.

Podemos executar nosso contêiner PHP como um usuário que não seja root usando a diretiva USER no Dockerfile, para que o contêiner seja executado no contexto de um usuário ou grupo com o mínimo possível de privilégios.

Se uma imagem base do Docker não incluir um usuário com poucos privilégios, podemos adicionar um usuário que não seja root durante o processo de criação da imagem. Ele ficará disponível para uso ao criar uma nova imagem de contêiner, como mostra o Dockerfile a seguir:

FROM php:7.4-cli
# the command below adds a new user or a group with a userid 1002
RUN groupadd -g 1002 appuser && \
    useradd -r -u 1002 -g appuser appuser
# command below changes a default root user to one with non-root privileges
USER appuser
CMD ["touch", "/root/example.txt"]

As imagens oficiais de contêiner PHP incluem uma conta de usuário sem privilégios chamada nobody. Portanto, se você estiver criando uma imagem de contêiner baseada em uma das imagens base oficiais do Docker, poderá usar esse usuário em vez de criar um manualmente, como demonstrado acima:

FROM php:7.4-cli
USER nobody
CMD ["touch", "/root/example.txt"]

Agora, se executarmos a imagem do Docker no modo interativo e tentarmos ver o arquivo de texto criado para o usuário root no Dockerfile, veremos que não temos permissão:

$ cat /root/example.txt
cat: /root/example.txt: Permission denied

A principal conclusão é que evitar o uso de root tanto no ambiente de execução quanto dentro dos contêineres significa que uma imagem de aplicação Docker maliciosa, ou uma aplicação comprometida em um contêiner, precisaria realizar dois ataques bem-sucedidos de escalonamento de privilégios para invadir o sistema operacional host onde o contêiner está sendo executado e, a partir daí, avançar lateralmente.

No entanto, nem sempre é possível usar contêineres rootless. Às vezes, aplicações conteinerizadas precisam acessar hardware, como uma GPU. Felizmente, podemos adicionar outras camadas de defesa.

Corrija vulnerabilidades em contêineres com ferramentas automatizadas

Muitas vulnerabilidades potenciais podem estar escondidas nos contêineres. Bibliotecas e aplicações incluídas na imagem base, assim como pacotes adicionais instalados, podem conter CVEs ou outras vulnerabilidades. Se isso acontecer, como você vai saber? A maioria das equipes de desenvolvimento e DevOps não tem tempo para acompanhar manualmente o histórico de segurança de cada pacote instalado nos contêineres. 

Felizmente, a análise automatizada de contêineres pode ajudar. O Snyk Container é gratuito e pode analisar nossas imagens automaticamente, avisando de imediato sobre vulnerabilidades nos pacotes e nas bibliotecas de código aberto dentro do contêiner. Assim, podemos implementar correções assim que uma vulnerabilidade surgir, antes que invasores possam explorá-la. A Snyk também propõe correções automaticamente, abrindo pull requests com uma imagem base atualizada e as tags de imagem recomendadas.

Com a Snyk, é rápido e fácil analisar nossos contêineres em busca de vulnerabilidades. Se tivermos Node.js e npm instalados, basta executar npm install snyk@latest -g para instalar a Snyk CLI.

Em seguida, execute:

snyk auth

Esse comando abrirá uma página de autenticação no navegador:

Página da Snyk solicitando que os usuários autentiquem a máquina para usar a CLI da Snyk, com um botão “Authenticate”

"blog-php-container-authenticateDepois que clicarmos no botão Authenticate, uma mensagem de autenticação bem-sucedida aparecerá no terminal.

Agora, podemos usar a Snyk CLI para analisar nossos contêineres executando:

snyk container test <your-image>

Ao executar o comando em uma imagem base do PHP 7.4, obtemos o seguinte resultado:

A análise do terminal da imagem base php:7.4.30-cli-bullseye aponta 87 vulnerabilidades: 2 críticas, 4 altas, 2 médias e 79 baixas.
A verificação de contêineres do Snyk encontrou 87 problemas na imagem base.

O ideal é executar uma análise de contêiner no nosso pipeline de CI/CD para garantir que nunca implantemos um contêiner vulnerável em produção. Também podemos usar o comando de monitoramento de contêineres para enviar à Snyk as informações dos testes da imagem. Assim, a Snyk pode exibir essas informações no painel e nos avisar sobre possíveis vulnerabilidades futuras na imagem.

snyk container monitor <your-image>

Ao executar o comando na mesma imagem PHP que acabamos de testar, obtemos o seguinte resultado:

Visão geral da imagem Docker mostrando a imagem PHP 7.4 CLI, o sistema operacional de destino Debian 11 e recomendações para atualizar a imagem base

Fácil, não é? E ainda não terminamos. Também podemos usar o Snyk Code para garantir que nosso código PHP esteja seguro antes de conteinerizá-lo.

Acesse a pasta onde está o arquivo de manifesto da sua aplicação PHP e execute o comando abaixo para ver o resultado:

snyk code test

Podemos executar um teste do Snyk Code em um projeto Laravel antigo para verificar um cenário comum: encontrar vulnerabilidades em um projeto PHP desatualizado, mas ainda em funcionamento. Veja o resultado abaixo:

Saída do terminal listando vulnerabilidades de alta gravidade no framework Laravel, incluindo injeção de SQL, validação inadequada de entradas e execução remota de código.

Assim como no monitoramento de contêineres, também podemos permitir que a Snyk monitore nossa base de código executando snyk monitor no diretório principal da aplicação PHP. Em seguida, veremos a aplicação no painel da Snyk.

Painel de projetos do Snyk exibindo vulnerabilidades recém-divulgadas no arquivo composer.lock do projeto Laravel.

A análise de segurança no nível dos contêineres e do código é uma excelente forma de garantir que entregamos contêineres e código seguros.

Use imagens de contêiner confiáveis

Uma forma de proteger nossos contêineres PHP é obter imagens de registros online seguros e confiáveis. É menos provável que esses registros contenham imagens com código malicioso ou desatualizado que possa expor nosso ambiente de contêineres a uma violação de dados. O Docker Hub, por exemplo, oferece várias imagens confiáveis, verificadas minuciosamente pelo Docker em busca de vulnerabilidades e cujos fornecedores também são verificados pelo Docker.

No entanto, nem todas as imagens do Docker Hub são confiáveis. Ao usar registros online, devemos verificar o conteúdo das imagens em busca de possíveis vulnerabilidades de segurança. Podemos analisar a imagem em busca de código malicioso que ameace o contêiner antes de baixá-la para o sistema host. Para garantir que essa etapa nunca seja ignorada, podemos integrar diretamente uma ferramenta de segurança como a Snyk às nossas ferramentas ou fluxos de trabalho de desenvolvimento para monitorar e corrigir possíveis vulnerabilidades nos contêineres.

Além de fazer varreduras, podemos garantir o uso de imagens de contêiner confiáveis recorrendo ao Docker Hub, ao programa Docker Verified Publisher e às Docker Official Images. O programa Docker Verified Publisher valida se as imagens obtidas por esse canal vêm de fontes confiáveis, evitando que os usuários baixem imagens inseguras de repositórios falsos.

Outra opção é usar imagens verificadas pelo Docker Content Trust. O Docker 1.8 introduziu o Docker Content Trust para reforçar a assinatura digital e a autenticação de imagens. A assinatura de imagens valida a origem de uma imagem de contêiner e confirma que ela não foi adulterada. Além disso, estabelece políticas que determinam quais imagens validadas os usuários podem baixar para seus sistemas.

Mesmo usando imagens oficiais do Docker obtidas de publishers verificados pelo Docker ou pelo Docker Content Trust para proteger o ambiente de contêineres, é essencial usar o Snyk para proteger nossos contêineres.

A segurança dos contêineres PHP também é responsabilidade dos desenvolvedores

Proteger contêineres PHP contra possíveis ameaças à segurança exige implementar várias técnicas ao longo do ciclo de vida da aplicação — da compilação à implantação e à execução. Além de seguir as práticas recomendadas de segurança para contêineres em aplicações PHP, podemos contar com o Snyk para ajudar a manter a segurança dos contêineres usando ferramentas automatizadas, como:

  • Testes de segurança automatizados em pipelines de CI/CD, como as integrações com GitHub Actions ou AWS Code Pipeline

  • Inteligência de segurança unificada para contêineres e código-fonte

  • Integração com Kubernetes para monitorar e observar contêineres nos clusters Kubernetes em busca de vulnerabilidades novas ou já existentes

  • Uma abordagem que prioriza os desenvolvedores e identifica problemas de segurança no seu próprio código PHP, facilitando a correção — mesmo para quem não tem ampla experiência em segurança

Snyk Container é uma ferramenta de gerenciamento de vulnerabilidades em contêineres que ajuda a identificar e resolver problemas de segurança de forma completa e eficiente. Com verificações integradas à IDE, integração automatizada com CI/CD, análise nativa de repositórios Git e testes no ambiente de produção, o Snyk Container protege contêineres e workloads Kubernetes durante todo o ciclo de vida do desenvolvimento de software.

Segurança de contêineres que prioriza os desenvolvedores

O Snyk encontra e corrige automaticamente vulnerabilidades em imagens de contêiner e workloads do Kubernetes.

Além disso, o Snyk ajuda a identificar vulnerabilidades integrando a análise de segurança às ferramentas de desenvolvimento, como VS-Code e JetBrains, durante o desenvolvimento das aplicações. Assim, você recebe mais informações sobre os tipos de vulnerabilidade e as correções recomendadas.

O Snyk também ajuda os desenvolvedores a identificar vulnerabilidades que comprometem a segurança dos contêineres e corrige esses problemas automaticamente. Assim, aumenta a produtividade e permite que as equipes de desenvolvimento dediquem menos tempo à correção de código e mais tempo à criação de aplicações. Crie sua conta gratuita hoje mesmo. Você também pode experimentar nossa ferramenta online gratuita de análise de código PHP para ver como o Snyk Code analisa seu código em busca de problemas de segurança e qualidade.