Análise Técnica do Módulo de Rotas no Scanner de Vulnerabilidades Xunfeng

O módulo de roteamento principal do sistema Xunfeng, projetado para auditoria automatizada e gestão de ativos em redes corporativas, é construído sobre o microframework Flask e o MongoDB. A camada de apresentação consolida a lógica de interface, orquestrando consultas paginadas, gerenciamento de tarefas de varredura, sicnronização de extensões e controle de acesso. A arquitetura segue um padrão baseado em decoradores para validar sessões e isolar riscos de requisições cross-site antes da execução das rotas.

Camada de Proteção e Middleware

A validação de estado examina o objeto de sessão global para confirmar credenciais ativas. Caso o marcador de autenticação esteja ausente ou inválido, o fluxo é interrompido e redirecionado para o ponto de entrada. De forma similar, a mitigação de CSRF analisa o cabeçalho de origem, comparando o domínio requisitante com o host da aplicação para descartar chamadas externas maliciosas.


from functools import wraps
from flask import session, redirect, url_for

def exigir_autenticacao(view_func):
    @wraps(view_func)
    def validador_sessao(*args, **kwargs):
        estado = session.get('usuario_validado')
        if estado == 'ativo':
            return view_func(*args, **kwargs)
        return redirect(url_for('endpoint_login'))
    return validador_sessao

def proteger_csrf(view_func):
    @wraps(view_func)
    def validador_origem(*args, **kwargs):
        ref = request.referrer
        if ref and request.host in ref:
            return view_func(*args, **kwargs)
        return redirect(url_for('tratamento_erro'))
    return validador_origem

Consulta de Ativos e Paginação

A interface de busca processa strings de consulta contendo múltiplos endereços IP, converte a entrada para filtros nativos do MongoDB e aplica ordenação decrescente por timestamp. O mecanismo de paginação calcula dinamicamente os limites e deslocamentos (offsets), retornando os dados processados junto com o contador total para renderização no front-end.


@app.route('/buscar')
@exigir_autenticacao
def listar_ativos():
    termo = request.args.get('query', '').strip()
    pagina = max(int(request.args.get('pg', 1)), 1)
    
    if termo:
        segmentacao = termo.split(';')
        filtro_db = converter_para_mongo(segmentacao)
        cursor = db.inventario.find(filtro_db).sort('registro_ts', -1)
        cursor.limit(itens_por_pagina).skip((pagina - 1) * itens_por_pagina)
        
        return render_template('painel.html', 
                               dados=cursor, 
                               total_registros=cursor.count(),
                               termo_entrada=termo)
    return render_template('painel.html', dados=[], total_registros=0)

Orquestração e Detalhamento de Tarefas

A criação de novos trabalhos de escaneamento valida a lista de alvos, normaliza pares de IP/porta e persiste os metadados na coleção de tarefas. A visualização de resultados agrupa as execuções por lotes temporais. Para evitar latência em conjuntos volumosos, a aplicação pré-carrega os hostnames em um mapa de hash local, unindo-os aos registros de vulnerabilidade durante a iteração.


@app.route('/detalhar_job')
@exigir_autenticacao
def exibir_job():
    job_id = request.args.get('id_tarefa')
    data_lote = request.args.get('lote_data')
    saida_formatada = []
    
    job = db.tarefas.find_one({'_id': ObjectId(job_id)})
    if job:
        lotes = db.vulnerabilidades.distinct('execucao_em', {'tarefa_ref': ObjectId(job_id)})
        if not data_lote and lotes:
            lotes.sort(reverse=True)
            data_lote = lotes[0]
            
        if data_lote:
            filtro = {'tarefa_ref': ObjectId(job_id), 'execucao_em': data_lote}
            itens = db.vulnerabilidades.find(filtro).sort('detectado_em', -1)
            
            mapa_dns = {d['ip']: d.get('dns_name', '') 
                        for d in db.inventario.find({'dns_name': {'$ne': None}})}
                        
            for vuln in itens:
                vuln['host_name'] = mapa_dns.get(vuln['ip'], 'Indisponível')
                saida_formatada.append(vuln)
                
    return render_template('detalhes.html', resultados=saida_formatada)

Exportação de Dados e Gestão de Extensões

A geração de relatórios em formato XLS emprega a biblioteca xlwt para montagem em memória. As linhas são transformadas em tuplas, escritas sequencialmente e retornadas via resposta HTTP com cabeçalhos de toça de download. Paralelamente, o sistema permite a remoção de plugins, limpando tanto o documento no banco quanto o arquivo físico no disco.


@app.route('/sincronizar_extensao')
@exigir_autenticacao
@proteger_csrf
def baixar_plugin_remoto():
    identificador = request.args.get('cod_ext')
    registro = db.atualizacoes_disponiveis.find_one({'hash_unico': identificador})
    
    if not registro:
        return 'nao_encontrado', 404
        
    destino = os.path.join(CAMINHO_MODULOS, os.path.basename(registro['url']))
    urllib.urlretrieve(registro['url'], destino)
    
    if os.path.exists(destino):
        metadados_extra = {}
        extensao = destino.rsplit('.', 1)[-1]
        
        if extensao == 'py':
            nome_base = os.path.splitext(os.path.basename(destino))[0]
            mod = __import__(nome_base)
            metadados_extra = mod.exportar_metadados()
            metadados_extra['nome_arquivo'] = nome_base
        else:
            with open(destino, 'r') as f:
                metadados_extra = json.load(f)
            metadados_extra['nome_arquivo'] = destino
            
        documento_final = {
            'criado_em': datetime.utcnow(),
            'origem': 'repositorio_externo'
        }
        documento_final.update(metadados_extra)
        db.modulos.insert(documento_final)
        db.atualizacoes_disponiveis.update_one(
            {'hash_unico': identificador},
            {'$set': {'estado': 'instalado'}}
        )
        return 'operacao_concluida', 200
    return 'falha_download', 500

Parâmetros do Sistema e Controle de Sessão

O painel administrativo expõe configurações categorizadas por motor de execução, interpretando listas e escalares antes da persistência atômica. O fluxo de login valida as credenciais contra variáveis de configuração da aplicação e manipula o estado da sessão, enquanto as rotas de fallback mapeiam códigos de status HTTP para templates específicos de erro.


@app.route('/acesso', methods=['GET', 'POST'])
def controlar_acesso():
    if request.method == 'POST':
        credencial_usuario = request.form.get('login')
        credencial_senha = request.form.get('senha')
        if credencial_usuario == app.config['ADMIN_ID'] and credencial_senha == app.config['ADMIN_SECRET']:
            session['usuario_validado'] = 'ativo'
            return redirect(url_for('listar_ativos'))
        return redirect(url_for('controlar_acesso'))
    return render_template('login_view.html')

@app.route('/sair')
@exigir_autenticacao
def encerrar_acesso():
    session.clear()
    return redirect(url_for('controlar_acesso'))

@app.route('/erro_navegacao')
def exibir_404():
    return render_template('erro_404.html'), 404

@app.route('/erro_servidor')
def exibir_500():
    return render_template('erro_500.html'), 500

Tags: flask-framework mongodb-pymongo web-vulnerability-scanner csrf-middleware asset-inventory

Publicado em 8-18 00:45