feat: sync timezone to America/Sao_Paulo, add diagnostic scripts to producao/scripts, and update PSDE docs

This commit is contained in:
João Pedro Toledo Goncalves 2026-02-08 15:54:09 -03:00
parent be7b271357
commit a5788fc66d
6 changed files with 163 additions and 7 deletions

View File

@ -93,7 +93,24 @@ O repositório conta com um script de automação híbrido (`producao/scripts/de
- **Causa**: O arquivo `snippets/modsecurity.conf` já define `modsecurity_rules_file`. Se você incluir esse snippet E também definir a diretiva `modsecurity_rules_file` no bloco `server` (ex: `ferreirareal.com.br.conf`), o Nginx falhará.
- **Solução**: Use apenas `include snippets/modsecurity.conf;` no bloco server. A diretiva `modsecurity_rules_file /etc/nginx/modsec/main.conf;` deve ficar comentada ou removida do vhost.
### 2. Falhas Silenciosas de Rollback
### 2. Scripts de Diagnóstico e Recuperação (2026-02-08)
Foram criados scripts auxiliares em `producao/scripts/` para situações de emergência ou validação profunda. Use-os com cautela:
- **`restore_nginx.py`**:
- **Função**: Força o upload do `nginx.conf` local para o servidor e reinicia o serviço.
- **Uso**: `python producao/scripts/restore_nginx.py`
- **Quando usar**: Se o `deploy_pathfinder.py` falhar ou se o Nginx não subir por erro de configuração crítica (ex: variáveis faltando).
- **`fetch_logs.py`**:
- **Função**: Baixa logs específicos do servidor para análise local.
- **Uso**: `python producao/scripts/fetch_logs.py`
- **Quando usar**: Para investigar ataques ou erros sem precisar logar via SSH.
- **`verify_time_and_logs.py`**:
- **Função**: Verifica a data do servidor e os últimos logs de acesso.
- **Uso**: `python producao/scripts/verify_time_and_logs.py`
- **Quando usar**: Para confirmar se o timezone está correto (-0300) e se o Nginx está gerando logs novos.
### 3. Falhas Silenciosas de Rollback
- **Cuidado**: O script `deploy_pathfinder.py` executa um rollback automático se `nginx -t` falhar.
- **O que acontece**: O script restaura o backup anterior e reinicia o Nginx. Isso faz o deploy parecer bem-sucedido (exit code 0), mas seus arquivos novos foram descartados.
- **Verificação**: **SEMPRE** verifique o timestamp dos arquivos remotos após um deploy crítico para garantir que foram atualizados:

View File

@ -13,7 +13,7 @@ A configuração é modular para permitir manutenção rápida e alta disponibil
- `snippets/`: Componentes reutilizáveis (SSL, Proxy, Cache, WAF, Headers).
- `modsec/`: Configuração do ModSecurity, regras **OWASP CRS v4** e tunings específicos.
- `dynamic/`: Arquivos modificados em tempo real (ex: `blacklist.conf` pelo Fail2Ban).
- `scripts/`: Scripts de utilidade (Ex: `install_modsecurity.sh`).
- `scripts/`: Scripts de automação e diagnóstico (`deploy_pathfinder.py`, `restore_nginx.py`, `fetch_logs.py`).
---
@ -78,9 +78,9 @@ O Pathfinder Proxy utiliza o **ModSecurity v3** compilado sob medida para o Ngin
---
## 🧠 Motor de Segurança PSDE "Elite" (7-Vector Matrix)
## 🧠 Motor de Segurança PSDE "Elite" (8-Vector Matrix)
Diferente de firewalls comuns, o Pathfinder utiliza uma **Matriz de Pontuação Combinatória** no `security_maps.conf` que analisa 7 vetores simultâneos:
Diferente de firewalls comuns, o Pathfinder utiliza uma **Matriz de Pontuação Combinatória** no `security_maps.conf` que analisa 8 vetores simultâneos:
1. **🛡️ Bot:** Bloqueio de 600+ user-agents maliciosos.
2. **🌐 URI:** Acesso a arquivos sensíveis e assinaturas de CVEs recentes.
@ -89,9 +89,10 @@ Diferente de firewalls comuns, o Pathfinder utiliza uma **Matriz de Pontuação
5. **🌍 Geo:** Risco por país (CN, RU, KP, IR) via **GeoIP2**.
6. **🚦 Protocol:** Violações como User-Agents vazios ou falsificados.
7. **🔗 Referer:** 400+ domínios de spam e phishing bloqueados instantaneamente.
8. **🤯 Header:** Detecção de anomalias em cabeçalhos customizados (ex: React2Shell CVE-2025-55182).
### 📈 Lógica de Decisão
- **Nivel 3 (ATAQUE_CRITICO)**: Payloads maliciosos, Referer Spam ou qualquer combinação de 3+ vetores.
- **Nivel 3 (ATAQUE_CRITICO)**: Payloads maliciosos, Referer Spam, Headers Corrompidos ou combinação de 3+ vetores.
- **Nivel 2 (RISCO_ALTO)**: Combinação de 2 vetores de risco (ex: Bot + Geo-Risco).
- **Nivel 1 (SUSPEITO)**: Detecção de sinais individuais.

View File

@ -1,4 +1,5 @@
# NGINX Master Configuration - Pathfinder Proxy
# Nginx Master Configuration - Pathfinder Proxy
env TZ=America/Sao_Paulo;
# Load essential modules
load_module modules/ngx_http_modsecurity_module.so;
@ -89,7 +90,7 @@ http {
access_log /var/log/nginx/access_json.log detailed_proxy;
# Logging Human Readable - For Docker Logs / User
access_log /dev/stdout combined;
# access_log /dev/stdout combined;
# SSL Settings (Global)
ssl_session_cache shared:SSL:50m;

44
scripts/fetch_logs.py Normal file
View File

@ -0,0 +1,44 @@
import paramiko
import os
import time
SERVER_HOST = "172.17.0.253"
SERVER_USER = "itguys"
PASSWORD = "vR7Ag$Pk"
def fetch_log(remote_path, local_path):
print(f"[*] Fetching {remote_path} -> {local_path}")
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
client.connect(SERVER_HOST, username=SERVER_USER, password=PASSWORD)
# Usando sudo cat para garantir acesso
stdin, stdout, stderr = client.exec_command(f"echo '{PASSWORD}' | sudo -S tail -n 50 {remote_path}", get_pty=False)
# Captura a saída
content = stdout.read().decode('utf-8')
err = stderr.read().decode('utf-8')
if content:
with open(local_path, 'w', encoding='utf-8') as f:
f.write(content)
print(f" [OK] Salvo em {local_path}")
else:
print(f" [!] Nenhum conteúdo ou erro: {err}")
client.close()
except Exception as e:
print(f" [!] Erro: {e}")
if __name__ == "__main__":
if not os.path.exists("logs"):
os.makedirs("logs")
fetch_log("/etc/nginx/nginx.conf", "logs/remote_nginx.conf")
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(SERVER_HOST, username=SERVER_USER, password=PASSWORD)
fetch_log("/var/log/nginx/ferreirareal.com.br.access.log", "logs/ferreirareal.access.log")
fetch_log("/var/log/nginx/access.log", "logs/global.access.log")

58
scripts/restore_nginx.py Normal file
View File

@ -0,0 +1,58 @@
import paramiko
import os
SERVER_HOST = "172.17.0.253"
SERVER_USER = "itguys"
PASSWORD = "vR7Ag$Pk"
def restore_nginx():
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(SERVER_HOST, username=SERVER_USER, password=PASSWORD)
local_file = "producao/nginx/nginx.conf"
remote_tmp = "/tmp/nginx.conf"
dest_file = "/etc/nginx/nginx.conf"
# 1. Upload to /tmp
print(f"[*] Uploading {local_file} -> {remote_tmp}")
sftp = client.open_sftp()
sftp.put(local_file, remote_tmp)
sftp.close()
# 2. Check File Difference (Optional but good for log)
cmd = f"echo '{PASSWORD}' | sudo -S diff {remote_tmp} {dest_file}"
stdin, stdout, stderr = client.exec_command(cmd)
# print(stdout.read().decode()) # Might be large
# 3. Move to /etc/nginx/
print(f"[*] Overwriting {dest_file}...")
cmd = f"echo '{PASSWORD}' | sudo -S cp {remote_tmp} {dest_file}"
stdin, stdout, stderr = client.exec_command(cmd)
print(stdout.read().decode())
print(stderr.read().decode())
# 4. Test Config
print("[*] Testing Nginx Config...")
cmd = f"echo '{PASSWORD}' | sudo -S nginx -t"
stdin, stdout, stderr = client.exec_command(cmd)
out = stdout.read().decode()
err = stderr.read().decode()
print(out)
print(err)
if "successful" in err or "successful" in out:
# 5. Restart
print("[*] Restarting Nginx...")
cmd = f"echo '{PASSWORD}' | sudo -S systemctl restart nginx"
stdin, stdout, stderr = client.exec_command(cmd)
print(stdout.read().decode())
print(stderr.read().decode())
print("[*] DONE. Service should be UP.")
else:
print("[!] Config Test Failed. Not restarting.")
client.close()
if __name__ == "__main__":
restore_nginx()

View File

@ -0,0 +1,35 @@
import paramiko
import time
SERVER_HOST = "172.17.0.253"
SERVER_USER = "itguys"
PASSWORD = "vR7Ag$Pk"
def verify():
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(SERVER_HOST, username=SERVER_USER, password=PASSWORD)
with open("logs/verify_logs.txt", "w", encoding="utf-8") as f:
f.write("--- Server Date ---\n")
cmd = f"echo '{PASSWORD}' | sudo -S date"
stdin, stdout, stderr = client.exec_command(cmd)
f.write(stdout.read().decode())
f.write("\n--- Generating Request ---\n")
cmd = "curl -v -k -I https://127.0.0.1/robots.txt"
stdin, stdout, stderr = client.exec_command(cmd)
f.write(stdout.read().decode())
f.write(stderr.read().decode())
time.sleep(2)
f.write("\n--- Latest Log Entries ---\n")
cmd = f"echo '{PASSWORD}' | sudo -S tail -n 2 /var/log/nginx/access_json.log"
stdin, stdout, stderr = client.exec_command(cmd)
f.write(stdout.read().decode())
client.close()
if __name__ == "__main__":
verify()