Depois de publicar nosso artigo sobre Phishing de Quarta Geração, recebi dezenas de mensagens perguntando: "OK, entendi o problema. Mas o que eu faço na prática?" Este tutorial é a resposta.
Vamos construir, do zero, um sistema de detecção de phishing que:
- Roda 100% local — seus dados nunca saem da sua máquina
- Usa IA (Llama 3 via Ollama) para analisar conteúdo suspeito
- Pode ser integrado a navegadores e clientes de e-mail
- Custa zero em licenças e APIs
Não é teoria. Eu uso uma versão mais robusta deste sistema no meu dia a dia, e ele já me salvou de pelo menos dois ataques convincentes. Vamos ao código.
Pré-requisitos
Antes de começar, certifique-se de ter:
- Python 3.10+ instalado
- Ollama instalado e funcionando (ollama.com)
- GPU recomendada: NVIDIA com 8GB+ VRAM (RTX 3060 ou superior). Funciona em CPU, mas será mais lento
- RAM: Mínimo 16GB
- Conhecimento básico de Python e terminal
Verificando se o Ollama está instalado
ollama --version
# Deve mostrar a versão. Se não, instale em ollama.com
# Baixe o modelo Llama 3 8B
ollama pull llama3
Passo 1: Configurando o Ambiente
# Crie um diretório para o projeto
mkdir phishing-detector && cd phishing-detector
# Crie e ative o ambiente virtual
python -m venv venv
source venv/bin/activate # No Windows: venv\Scripts\activate
# Instale as dependências
pip install ollama requests beautifulsoup4 fastapi uvicorn
Estrutura do projeto
phishing-detector/
├── analyzer.py # Motor de análise com IA
├── url_checker.py # Verificador de URLs
├── api.py # API FastAPI para integração
├── config.py # Configurações
└── whitelist.txt # Domínios confiáveis
Passo 2: O Motor de Análise
Este é o coração do sistema. O segredo está no Prompt Engineering — precisamos que a IA aja como um analista de segurança sênior.
# analyzer.py
import ollama
import json
import re
SYSTEM_PROMPT = """Você é um analista sênior de cibersegurança especializado em
detecção de phishing. Analise o conteúdo fornecido e retorne APENAS um JSON válido
com a seguinte estrutura:
{
"score": <número de 0 a 100, onde 100 = certeza de phishing>,
"riscos": [<lista de riscos identificados>],
"sinais": [<lista de sinais suspeitos encontrados>],
"recomendacao": "<ação recomendada: seguro|suspeito|perigoso>"
}
Critérios de análise:
- Urgência artificial ("aja agora", "última chance")
- Solicitação de credenciais ou dados pessoais
- Links para domínios suspeitos ou recém-registrados
- Erros de domínio (caracteres Unicode, typosquatting)
- Tom emocional manipulativo (medo, ganância, curiosidade)
- Inconsistências entre remetente declarado e domínio real
- Ofertas irrealistas ou pressão temporal
"""
def analisar_conteudo(texto: str, modelo: str = "llama3") -> dict:
"""Analisa texto para sinais de phishing usando IA local."""
try:
response = ollama.generate(
model=modelo,
system=SYSTEM_PROMPT,
prompt=f"Analise este conteúdo para phishing:\n\n{texto}",
options={"temperature": 0.1} # Baixa temperatura para consistência
)
# Extrair JSON da resposta
resultado = response["response"]
json_match = re.search(r'\{.*\}', resultado, re.DOTALL)
if json_match:
return json.loads(json_match.group())
return {"score": 50, "riscos": ["Não foi possível analisar"],
"sinais": [], "recomendacao": "suspeito"}
except Exception as e:
return {"score": -1, "riscos": [f"Erro na análise: {str(e)}"],
"sinais": [], "recomendacao": "erro"}
def analisar_url(url: str, modelo: str = "llama3") -> dict:
"""Analisa uma URL para sinais de phishing."""
prompt_url = f"""Analise esta URL para sinais de phishing:
URL: {url}
Verifique:
1. Domínio legítimo ou typosquatting?
2. Caracteres Unicode enganosos?
3. Subdomínios suspeitos?
4. HTTPS presente?
5. Padrão de URL consistente com o serviço declarado?
"""
try:
response = ollama.generate(
model=modelo,
system=SYSTEM_PROMPT,
prompt=prompt_url,
options={"temperature": 0.1}
)
resultado = response["response"]
json_match = re.search(r'\{.*\}', resultado, re.DOTALL)
if json_match:
return json.loads(json_match.group())
return {"score": 50, "riscos": ["Análise inconclusiva"],
"sinais": [], "recomendacao": "suspeito"}
except Exception as e:
return {"score": -1, "riscos": [f"Erro: {str(e)}"],
"sinais": [], "recomendacao": "erro"}
Dica importante sobre temperature
Uso temperature: 0.1 deliberadamente. Em segurança, não queremos "criatividade" — queremos consistência. Com temperature alta, o modelo pode variar demais entre análises do mesmo conteúdo.
Passo 3: Verificador de URLs
# url_checker.py
import requests
from bs4 import BeautifulSoup
from urllib.parse import urlparse
def extrair_conteudo_url(url: str) -> dict:
"""Extrai conteúdo de uma URL para análise."""
try:
# Headers que imitam navegador real
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 Chrome/120.0.0.0 Safari/537.36"
}
response = requests.get(url, headers=headers, timeout=10,
allow_redirects=True)
soup = BeautifulSoup(response.text, "html.parser")
# Extrair informações relevantes
titulo = soup.title.string if soup.title else "Sem título"
texto = soup.get_text(separator=" ", strip=True)[:2000]
# Verificar redirecionamentos
historico_urls = [r.url for r in response.history]
# Analisar formulários (sinais de coleta de credenciais)
forms = soup.find_all("form")
tem_login = any(
f.find("input", {"type": "password"}) for f in forms
)
parsed = urlparse(url)
return {
"titulo": titulo,
"texto": texto,
"dominio": parsed.netloc,
"https": parsed.scheme == "https",
"redirecionamentos": historico_urls,
"tem_formulario_login": tem_login,
"status_code": response.status_code
}
except requests.RequestException as e:
return {"erro": str(e)}
Passo 4: API para Integração
# api.py
from fastapi import FastAPI
from pydantic import BaseModel
from analyzer import analisar_conteudo, analisar_url
from url_checker import extrair_conteudo_url
app = FastAPI(title="Phishing Detector Local")
class TextoInput(BaseModel):
texto: str
class UrlInput(BaseModel):
url: str
@app.post("/analisar/texto")
def analisar_texto_endpoint(input: TextoInput):
"""Analisa um texto (e-mail, mensagem) para phishing."""
resultado = analisar_conteudo(input.texto)
return resultado
@app.post("/analisar/url")
def analisar_url_endpoint(input: UrlInput):
"""Analisa uma URL para phishing."""
# Primeiro extrai o conteúdo da página
conteudo = extrair_conteudo_url(input.url)
if "erro" in conteudo:
return {"score": 70, "riscos": ["URL inacessível - possível phishing"],
"sinais": [conteudo["erro"]], "recomendacao": "suspeito"}
# Combinar análise de URL + conteúdo da página
analise_url = analisar_url(input.url)
analise_conteudo = analisar_conteudo(
f"Título: {conteudo['titulo']}\n"
f"Domínio: {conteudo['dominio']}\n"
f"Tem formulário de login: {conteudo['tem_formulario_login']}\n"
f"HTTPS: {conteudo['https']}\n"
f"Redirecionamentos: {conteudo['redirecionamentos']}\n"
f"Conteúdo: {conteudo['texto'][:1000]}"
)
# Score combinado (maior peso para análise de conteúdo)
score_final = int(
analise_url.get("score", 50) * 0.4 +
analise_conteudo.get("score", 50) * 0.6
)
return {
"score": score_final,
"analise_url": analise_url,
"analise_conteudo": analise_conteudo,
"dados_pagina": {
"titulo": conteudo["titulo"],
"dominio": conteudo["dominio"],
"https": conteudo["https"],
"redirecionamentos": len(conteudo.get("redirecionamentos", [])),
"tem_login": conteudo["tem_formulario_login"]
}
}
@app.get("/health")
def health():
return {"status": "ok", "modelo": "llama3"}
Rodando a API
uvicorn api:app --host 0.0.0.0 --port 8000 --reload
Testando
# Testar análise de texto
curl -X POST http://localhost:8000/analisar/texto \
-H "Content-Type: application/json" \
-d '{"texto": "URGENTE: Sua conta será bloqueada em 24h. Clique aqui para verificar: http://g00gle-security.tk/verify"}'
# Testar análise de URL
curl -X POST http://localhost:8000/analisar/url \
-H "Content-Type: application/json" \
-d '{"url": "https://google.com"}'
Passo 5: Otimização para Produção
Antes de usar este sistema no dia a dia, considere estes ajustes:
Performance
- Quantização GGUF: Use modelos quantizados para economizar memória. O
llama3:8b-instruct-q4_0usa ~4GB de VRAM com perda mínima de qualidade. - Cache de resultados: Implemente cache para URLs já analisadas (com TTL de 24h) para evitar reprocessamento.
- Batch processing: Para análise de e-mails em massa, agrupe as análises e processe em lote.
Segurança
- Whitelist de domínios: Mantenha uma lista de domínios confiáveis (google.com, microsoft.com, etc.) para evitar falsos positivos.
- Rate limiting: Limite as requisições à API para evitar abuso.
- Logs de auditoria: Registre todas as análises para alimentar seu SIEM e melhorar o modelo ao longo do tempo.
Integração com ferramentas existentes
O sistema pode ser integrado com:
- Extensões de navegador: Um popup que analisa links antes de clicar
- Clientes de e-mail: Análise automática de e-mails recebidos via IMAP
- Slack/Teams: Bot que analisa links compartilhados em canais corporativos
- SIEM: Envio de alertas para Splunk, ELK ou similares
Limitações e Considerações
Preciso ser honesto sobre o que este sistema não faz:
- Não é infalível: Phishing muito sofisticado pode enganar o modelo
- Não substitui treinamento: Pessoas treinadas são a última linha de defesa
- Latência: Cada análise leva 1-5 segundos (dependendo do hardware)
- Falsos positivos: E-mails legítimos com urgência real podem ser sinalizados
A melhor abordagem é usar este sistema como uma camada adicional em uma estratégia de defesa em profundidade.
Conclusão
O futuro da defesa cibernética é local e autônomo. Com ferramentas como Ollama e modelos open-source, qualquer empresa pode ter sua própria inteligência de ameaças sem depender de APIs externas ou comprometer a privacidade de seus dados.
Este tutorial é um ponto de partida. Na prática, você vai querer adicionar mais fontes de dados (headers de e-mail, metadados de anexos, reputação de domínio), integrar com feeds de threat intelligence e criar dashboards de monitoramento.
Se quiser entender melhor as ameaças contra as quais estamos nos defendendo, leia nosso artigo sobre Phishing Gen4 e como ele está burlando MFA. E para a abordagem mais ampla de IA local para segurança corporativa, confira o artigo sobre soberania de dados e inteligência air-gapped.
O código completo deste tutorial está disponível para uso e modificação. Se implementar melhorias, compartilhe nos comentários — a segurança é um esforço coletivo.




