O primeiro script (e post no TabNews) da minha vida
Introdução
Fala pessoal,
Como programador iniciante, estou um pouco acanhado de postar aqui, principalmente diante de tanta gente talentosa e experiente, mas como houveram vários incentivos para que eu fosse em frente, aqui estou eu.
Aliás, apesar de apresentar o código que fiz, o objetivo não é necessariamente esse, tanto que no título não coloquei "Script para bloquear requisições XMLRPC", que seria o certo haha Meu objetivo aqui é um pouco mais empírico: quero inspirar aqueles que estão iniciando na área a também resolverem problemas do seu dia-a-dia com a programação! Então, apesar de talvez o conteúdo não ser muito útil para a maioria de vocês, eu quero na verdade estimular o uso da tecnologia na nossa vida. Bora pro conteúdo.
block-xmlrpc-requests
Script para adicionar bloco de código que bloqueia requisições ao arquivo xmlrpc.php, em todas as instalações WordPress de um servidor.
Por que criei esse script?
Como administrador de uma hospedagem de sites, eu estava recebendo muitas mensagens do meu firewall com um aviso semelhante ao seguinte:
Time: Wed Apr 20 20:28:17 2022 -0300
IP: 185.189.115.108 (CZ/Czechia/pc-coupons.online)
Failures: 5 (XMLRPC)
Interval: 3600 seconds
Blocked: Permanent Block [LF_CUSTOMTRIGGER]
Numa rápida pesquisa, descobri que conseguiria resolver esse problema apenas implementando o código a seguir no arquivo .htaccess
:
<Files xmlrpc.php>
order deny,allow
deny from all
allow from xxx.xxx.xxx.xxx
</Files>
Mas copiar e colar o código em cada um dos sites, de modo manual, me parecia um pouco cansativo. Por isso criei o script.
Observações importantes
- É o primeiro código da minha vida hehe por isso, atente-se aos seguintes pontos:
- Podem existir vulnerabilidades;
- Podem existir erros ou "pontas soltas";
- Acho que pode ser escrito de maneira mais limpa;
- Não tenho experiência suficiente para analisar se consome muitos recursos do servidor (o que também depende do tamanho e capacidade do seu servidor) - ou seja, não tenho certeza se é saudável rodar esse código em outros ambientes (no meu foi tranquilo [eu acho]).
Conto com sua ajuda nos pontos acima :D
- O meu ambiente é um CentOS 7 com o painel CWP rodando. Pode ser que em outros ambientes você precise fazer alguma alteração no código (como a estrutura do diretório "home" ou o comando para reinicializar o Apache).
Código
echo "Procurando por instalações WordPress no servidor..."
find /home/ -type f -name "xmlrpc.php" -not -path "*wp-content*" -printf '%h\n' | sort -u >> wps.txt
readarray wps < wps.txt
echo "${#wps[@]} instalações encontradas!"
echo "Procurando por arquivos .htaccess que não contenham o código <Files xmlrpx.php>..."
for wp in ${wps[@]}
do
find $wp -maxdepth 1 -type f -name ".htaccess" | xargs -r grep -L "<Files xmlrpc.php>" >> files.txt
readarray files < files.txt
done
rm files.txt wps.txt
nfiles=${#files[@]}
if [ $nfiles == 0 ]
then
echo "Todos os arquivos já contém o código. Até mais!"
exit
else
if [ $nfiles == 1 ]
then
echo "01 arquivo encontrado!"
echo "Adicionando o código no arquivo..."
else
echo "${#files[@]} arquivos encontrados!"
echo "Adicionando o código nesses arquivos..."
fi
for file in ${files[@]}
do
echo "
#Block WordPress xmlrpc.php requests
<Files xmlrpc.php>
order deny,allow
deny from all
</Files>" >> $file
echo "Código adicionado em $file!"
done
fi
echo "Pronto!"
while true;
do
read -p "Necessário reiniciar o Apache para aplicar as configurações. Deseja reiniciar agora? [Y/n]" yn
case $yn in
[Yy]*) systemctl restart httpd.service; echo "Apache reiniciado com sucesso."; break;;
[Nn]*) exit;;
* ) echo "Entrada inválida.";;
esac
done
Explicação do código
Procura por diretórios em /home
que contenham o arquivo xmlrpc.php
, excluindo as subpastas wp-content
e armazena os valores num array:
find /home/ -type f -name "xmlrpc.php" -not -path "*wp-content*" -printf '%h\n' | sort -u >> wps.txt
readarray wps < wps.txt
Para cada diretório encontrado no comando anterior, executa uma busca por arquivos .htaccess
que não contenham o código <Files xmlrpc.php>
, adiciona-os a um arquivo temporário e armazena os valores num array:
Reconheço que aqui existe uma "ponta solta" no sentido que apenas a primeira linha do código está sendo buscada no arquivo, enquanto deveria ser todo o trecho. Porém, ainda não consegui resolver esse empecilho, então considere apenas um começo e conto com sua participação para melhorá-lo.
for wp in ${wps[@]}
do
find $wp -maxdepth 1 -type f -name ".htaccess" | xargs -r grep -L "<Files xmlrpc.php>" >> files.txt
readarray files < files.txt
done
Faz uma verificação do tamanho do array (ou seja, quantos arquivos foram encontrados) e, se for igual a zero, finaliza o código:
nfiles=${#files[@]}
if [ $nfiles == 0 ]
then
echo "Todos os arquivos já contém o código. Até mais!"
exit
Se tiver um ou mais arquivos encontrados, adiciona o bloco de código a cada um deles:
else
if [ $nfiles == 1 ]
then
echo "01 arquivo encontrado!"
echo "Adicionando o código no arquivo..."
else
echo "${#files[@]} arquivos encontrados!"
echo "Adicionando o código nesses arquivos..."
fi
for file in ${files[@]}
do
echo "
#Block WordPress xmlrpc.php requests
<Files xmlrpc.php>
order deny,allow
deny from all
</Files>" >> $file
echo "Código adicionado em $file!"
done
fi
Simples validação, com interação do usuário, para reiniciar o Apache após a execução das tarefas:
while true;
do
read -p "Necessário reiniciar o Apache para aplicar as configurações. Deseja reiniciar agora? [Y/n]" yn
case $yn in
[Yy]*) systemctl restart httpd.service; echo "Apache reiniciado com sucesso."; break;;
[Nn]*) exit;;
* ) echo "Entrada inválida.";;
esac
done
Considerações finais
Não hesite em deixar suas críticas ou sugestões. Estou aberto a melhorias!
Fiz esse código por hobbie e para exercitar meu conhecimento em programação, mas espero de coração que ele seja útil a alguém. Se for, deixe eu ficar sabendo, por favor! :)
Dica: você pode implementar como um cronjob
para executá-lo de tempos em tempos automaticamente no seu servidor (aqui eu vou deixar 1 vez por mês).
Meus próximos projetos
Tenho diversos projetos em mente e vou colocar alguns aqui para tentar te inspirar ainda mais. Lembre-se: a ideia não é ser necessariamente útil para todo mundo, e sim resolver problemas na sua vida que possam ser automatizados. Com o tempo, pode ser que a ideia de ouro surja ou, no mínimo, você terá um portfólio legal para apresentar no seu currículo. Divirta-se!
-
Um app para controle de gastos de veículo próprio utilizado a trabalho. Estou fazendo corridas no iComida como extra (não sei se posso citar marcas registradas aqui), e marcando a quilometragem diariamente de modo manual para contabilizar os gastos. Seria bacana automatizar esse processo.
-
Um web app que sirva como uma "ponte pix" para quem deseja cobrar seus clientes de maneira profissional e rápida. A ideia é que seja super prático de se cadastrar e usar, e tenha uma página semelhante ao Linktree porém exibindo apenas informações de pagamento. Penso em fazer um formato tipo (app.io/user/{valor}) onde no valor o usuário poderá digitar um
int
e, se possível, já apresentar o código pix e outras integrações abaixo relacionado ao valor digitado (o PicPay já meio que faz isso atualmente). -
Instalação limpa de um novo site WordPress. Repito diversas tarefas toda vez que crio um novo site: registrar domínio, criar conta no servidor, adicionar domínio na CloudFlare, configurar DNS e SSL, instalar o WP, configurar o WP (idioma, fuso-horário, permalinks...), instalar plugins, apagar o Hello World. Seria muito massa poder apenas digitar um domínio no terminal e deixar ele fazer todo esse processo, me liberando tempo e energia para focar na parte criativa.
Agradecimentos
Spoiler: puxação de saco ao Filipe kkk
Filipe, eu te agradeci publicamente no meu repositório do GitHub por me inspirar a trabalhar com tecnologia, e como não consegui postar no YouTube, não poderia perder esta oportunidade :D
- Ao Fábio da Bóson Treinamentos, pelo Curso de Shell Scripting, que foi muito útil ao escrever o meu primeiro código;
- Por toda a comunidade de programação em fóruns da internet.
Ah, e se você quiser apoiar: link do repositório no GitHub
Abraços!