Oculte a pasta .git de sua aplicação

Post publicado em 25/12/2017 16:39 Última atualização em 04/08/2019 20:38

[vc_row][vc_column][vc_column_text]OculteRemova a pasta .git de suas aplicações e previna-se desde exposição de dados sensíveis até completo clone, entenda um pouco mais sobre esta brecha facilmente explorada e saiba como a evitar. É comum que as hospedagens disponibilizem um diretório chamado www, public_html, public ou ainda httpdocs para que hospedemos nossas aplicações. Não é nenhum erro e é uma forma de padronizar as aplicações web. Mas podemos ter problema quando todo nosso código-fonte fica dentro de uma dessas pastas. Em aplicações com frameworks que isolam a lógica da pasta pública (Zend Framework, Symfony, Laravel, dentre outros) não existe esta preocupação porque a pasta do sistema de versionamento não está na área pública, no entanto aplicações como WordPress e outras, até mesmo soluções in-house podem apresentar o problema descrito a seguir.  

O problema

Exposição do diretório .git quando se está utilizando o sistema de versionamento git e todo o código-fonte fica hospedado dentro de uma pasta pública. Veja a imagem abaixo.

Consequências moderadas

Exposição de informações sensíveis de sua aplicação como URL do do repositório além de ser algo totalmente desnecessário que se esteja visível, muito menos ainda, indexado pelo Google.  

Consequências graves

Com um simples comando é possível clonar um site INTEIRO! Veja o exemplo real. Utilizando o programa wget em uma máquina com o Fedora, foi possível clonar um site inteiro apenas tendo acesso à pasta .git do mesmo. Atenção: o exemplo que listo é de um site que eu administro e acabei de assumir o projeto até então mantido por outra agência, jamais peguei serviço alheio.
$ wget --recursive dominio.com.br/.git/
O comando traz todo o conteúdo de .git para a pasta atual de nosso shell, para este exemplo: ~/ocultar-pasta. O resultado é este: Uma pasta com o nome do site clonado e dentro dela a pasta .git. De brinde também veio o arquivo robots.txt.   E então temos todo o código-fonte em nossas mãos. Não acredita? Basta rodar o comando git reset --hard e pronto!

Assustador não é mesmo? Ainda mais que na agência anterior versionaram tudo, inclusive plugins pagos e pasmem, 2 anos de uploads (2011 e 2012). Isso foi possível por causa de um erro básico: O desenvolvedor ao publicar simplesmente clonou o projeto na pasta pública. Não teve preocupação com boas práticas e muito menos com segurança. Em comentários por onde compartilhei, houveram alguns dizendo que a hospedagem não tem tratativa pra isso, portanto, tem uma parcela de culpa. Mas não, a hospedagem não tem culpa. Ela simplesmente não espera tal comportamento do programador (neste meu caso, dos programadores da agência antiga).  

Ok, mas e como resolver?

Inicialmente eu havia feito apenas um redirect (gambiarra, é claro), aí comecei a compartilhar este post em grupos de WhatsApp, Slack e Facebook. A cada novo share que eu dava, novas críticas construtivas para enfim lhe apresentar a solução correta. Por este post ter sido uma grande evolução, ao final do mesmo eu deixo as soluções que eu criei, uma delas gambiarra, (por favor, não façam daquele jeito) e a outra é apenas uma reinvenção da roda, funciona, mas tem uma solução mais recomendada.

A solução

A solução correta em termos de versionamento e segurança sem sombra de dúvidas é não deixar a pasta .git na área pública da aplicação. Isso pode ser feito com ferramentas de Integração Contínua (CI), git hooks, dentre outros processos automatizados de deploy. Por questões de complexidade e necessidades específicas de cada projeto, não abordarei nada relacionado à CI. A solução mais simples para resolver é com Git Hooks.

Deploy com Git Hooks

Divulguei este post no grupo PHP Community no WhatsApp e novamente recebi críticas que ajudaram a composição da solução. No fim este está se tornando meu primeiro post colaborativo, estou gostando da ideia. A dica foi do Alysson Azevedo, de Curitiba. A solução que ele sugeriu é bem simples, testei e tá aprovadíssima. Não requer nenhuma lib, apenas git hooks. Vou postar o link da solução que traduzi de um artigo em inglês para ajudar principalmente programadores iniciantes ou que ainda tem dificuldades em entender alguns termos em inglês. https://www.andrebian.com/deploy-com-git-hooks/   Após o break deixo as primeiras soluções que abordei apenas para caráter de informação, afinal de contas, mencionei que este foi um post em que diversos devs contribuíram e nada mais justo que eu exibir quais foram as soluções que apresentei antes de toda a evolução do mesmo (e já mencionada - Git Hooks e CI)   Este é o break! Este post é longo então faz o seguinte, dê uma pausa na leitura e pega um café que ainda tem muita coisa. Enquanto isso, deixa eu lhe oferecer o meu livro, veja o box abaixo.[/vc_column_text][us_cta title="Interesse em TDD?" title_size="h3" color="custom" bg_color="#422b72" text_color="#ffffff" btn_link="url:https%3A%2F%2Ftddcomphp.com.br||target:%20_blank|" btn_label="Conheça meu livro" btn_size="20px" btn_style="4"]
Então meu livro é perfeito pra você!
Pra ficar melhor ainda, tenho um cupom de 15% de desconto. Clique em "Conheça meu livro" e pegue o seu![/us_cta][vc_column_text]

Como prometido, abaixo segue a soluçãogambiarra apresentada antes de todas as contribuições.

Redirect - não faça isso!

Esta dica vem para sanar as necessidades de quem utiliza hospedagem com o server Apache, para Nginx ainda não realizei este procedimento, caso já tenha realizado este bloqueio, deixa a sua solução nos comentários que com certeza será de grande utilidade para os demais leitores. No arquivo .htaccess (caso não exista, crie-o na sua pasta pública) insira o seguinte trecho de código:
RedirectMatch 301 /.git /not-found
Com isso, sempre que uma requisição para https://dominio.com.br/.git for recebida, será redirecionada permanentemente (301) para https://dominio.com.br/not-found evitando assim a exposição da pasta e consequente exploração da mesma.

É obrigatório redirecionar para /not-found?

Não, mas é uma boa prática. Uma vez que redirecionamos para /not-found o erro 404 é lançado e a requisição se finda, diferente de redirecionar para /, por exemplo, que tentará obter todos os arquivos do site, não somente a pasta .git. Redirecionar para /not-found (ou qualquer URI inexistente na aplicação) é mais uma questão de segurança. Por que esta forma não é a recomendada? Porque não é a correta! Ela não resolve o problema, apenas o contorna.

Resultado

Após a regra aplicada no .htaccess do mesmo site clonado anteriormente o resultado é este: Ufa! Podemos dormir tranquilos agora (depois da contribuições que recebi afirmo que não, não podemos dormir tranquilos, para isso é preciso RESOLVER o problema, não apenas o contornar!).   Enfim, no dia 27/12/2017 recebi as primeiras críticas construtivas e a partir delas, criei este método para solucionar o problema. Ele na verdade é uma reinvenção da roda do que é apresentado no post sobre deploy com Git Hooks. Faz as coisas de maneira distinta mas o resultado é o mesmo, a pasta .git não estará mais presente na área pública da aplicação.  

Deploy com fabric

Como disse, não entrarei em detalhes sobre CI porque leva tempo e cada qual possui suas particularidades, mas se você quer uma maneira rápida, deixo uma dica, sem CI, somente com um script em fabric que menciono aqui.
  1. A aplicação versionada fica um nível acima da pasta pública (Ex: ~/nome-do-projeto)
  2. Toda vez que precisar sincronizar, entre em ~/nome-do-projeto e dê um git pull
  3. Copie somente ~/nome-do-projeto/.git para ~/public_html/.git
  4. Dê um reset --hard
  5. Remova a pasta ~/public_html/.git e outros relacionados ao Git.
Esta é uma solução muito simples sem utilizar CI, e o script para isso é esse:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#

from fabric.api import *

## global configuration

env.hosts = ['user@domain.com.br']
env.path  = '/home/user/nome-do-projeto'

''' Se necessário porta '''
## env.port = 2222

## configured commands

def deploy(version=None):
    ''' Executa o deploy no ambiente de PRODUÇÃO. '''

    ## sincroniza o repositório na pasta segura do server
    run("cd %s; git pull origin master" % (env.path))

    ## sincroniza a aplicação e produção (live)
    run("cd %s; cp .git ../public_html/.git; cd ../public_html; git reset --hard" % (env.path))

    ## E por último remove tudo relacionado ao Git da pasta pública
    run("cd %s; rm -rf ../public_html/.git*" % (env.path))

    print("Deploy finalizadornrn")
Lembrando somente que a pasta public_html é comum em hospedagens hostgator, para outras hospedagens pode ser diferente. Aí para realizar o deploy, pode ser de sua máquina mesmo (desde que tenha seguido o post de deploy com python):
fab deploy
 

Colaboraram com este post

  • Alysson Azevedo - Sugestão do Git Hooks
  • Jefferson Santos (mcgyver) - Juntamente do Wallace Batista contribuiu em questões de boas práticas com o Git
  • Wallace Batista (uselessdev) - Boas práticas com o Git
  • João Batista Neto (netojoaobatista) - Sugestão de melhoria nos updates dos textos (priorizar a solução correta para só depois mostrar como o post evoluiu)
[/vc_column_text][us_cta title="Tem interesse em Git?" color="light" btn_link="url:https%3A%2F%2Fandrebian.com%3Fs%3Dgit|||" btn_label="Ler mais" btn_style="3" btn_size="20px"]Temos bastante conteúdos relacionados ao git que com certeza você gostará.[/us_cta][/vc_column][/vc_row]


Scroll down