O maior portal de MU Online do Brasil — desde 2003
Tutorial Avançado Website

Como criar um painel de administração web para MU Online

Construa um painel de administração web seguro para o seu servidor de MU Online, com autenticação forte, controle de permissões, gestão de contas e personagens, banimentos, envio de itens e logs de auditoria completos.

GA Gabriel · Atualizado em 12 jul 2025 · ⏱ 15 de leitura
Resposta rápida

Chega um momento na vida de todo servidor de MU Online em que abrir o Navicat ou o SQL Server Management Studio para cada banimento, cada devolução de item e cada reset manual deixa de ser sustentável. É lento, é perigoso, não deixa rastro de quem fez o quê, e é impensável dar esse tipo de acesso a

Chega um momento na vida de todo servidor de MU Online em que abrir o Navicat ou o SQL Server Management Studio para cada banimento, cada devolução de item e cada reset manual deixa de ser sustentável. É lento, é perigoso, não deixa rastro de quem fez o quê, e é impensável dar esse tipo de acesso a um GM voluntário. A solução profissional é um painel de administração web: uma aplicação que expõe apenas as operações necessárias, com validação, controle de permissões e auditoria completa. Neste tutorial avançado você vai desenhar e construir esse painel do zero, com atenção especial à parte que mais gente ignora e que mais causa estrago — a segurança.

Um painel de administração é, por definição, o alvo mais valioso do seu servidor. Quem o compromete pode dar itens infinitos, banir jogadores legítimos, roubar contas e destruir a economia em minutos. Por isso, cada seção deste guia trata o painel como um sistema hostil por natureza: assuma que ele será atacado e projete-o para resistir. Todos os nomes de tabela, coluna e estrutura são exemplos típicos e variam por versão (Season 6, IGCN, MuEMU, Season 16+); confirme o schema real da sua distribuição antes de rodar qualquer comando.

Pré-requisitos

  • Ambiente com PHP 8.1+ e PDO (driver sqlsrv para SQL Server) ou stack equivalente (Node.js, .NET).
  • Acesso ao banco do jogo (SQL Server, comum em MU) e, opcionalmente, ao banco do site.
  • HTTPS válido no domínio do painel (Let's Encrypt).
  • Servidor web configurado para servir o painel em uma rota separada e protegida (subdomínio ou pasta com regras próprias).
  • Conhecimento de SQL parametrizado, sessões e hashing de senha.
  • Um plano de papéis: quem é Admin, quem é GM, o que cada um pode fazer.

> Regra de ouro: o banco de dados do jogo nunca deve estar acessível diretamente pela internet. O painel é a única ponte, e ela precisa ser blindada.

Arquitetura e camadas de segurança

Pense no painel como uma cebola de camadas. Um atacante precisa furar todas para causar dano. Cada camada é independente das outras.

  1. Rede: o painel roda em subdomínio próprio, atrás de HTTPS, idealmente com restrição de IP ou VPN para administradores.
  2. Autenticação: login com senha em hash forte (bcrypt/Argon2) e 2FA para admins.
  3. Autorização: cada ação verifica o papel do usuário (RBAC). Um GM não pode acessar rotas de admin.
  4. Validação: toda entrada é validada e todo SQL é parametrizado (nunca concatenado).
  5. Auditoria: cada ação sensível é registrada com quem, o quê, quando e de onde.
CamadaAmeaça que bloqueiaMecanismo
RedeVarredura e acesso externoHTTPS, restrição de IP, subdomínio
AutenticaçãoLogin indevidoHash de senha, 2FA, rate limit
AutorizaçãoEscalada de privilégioRBAC por papel
ValidaçãoSQL Injection, XSSPDO parametrizado, escape de saída
AuditoriaAbuso interno / negaçãoLog imutável de ações

Modelagem de usuários e papéis do painel

O painel tem seus próprios usuários, separados das contas do jogo. Um administrador do painel não é a mesma coisa que uma conta de jogador. Crie no banco do site:

CREATE TABLE admin_users (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    username    VARCHAR(40) UNIQUE NOT NULL,
    pass_hash   VARCHAR(255) NOT NULL,       -- bcrypt/argon2
    role        ENUM('admin','gm','support') NOT NULL DEFAULT 'support',
    totp_secret VARCHAR(64) NULL,            -- 2FA
    last_ip     VARCHAR(45) NULL,
    last_login  DATETIME NULL,
    active      TINYINT(1) DEFAULT 1,
    created_at  DATETIME DEFAULT CURRENT_TIMESTAMP
);

E a tabela de auditoria, o item mais importante do painel inteiro:

CREATE TABLE admin_audit (
    id          BIGINT AUTO_INCREMENT PRIMARY KEY,
    admin_id    INT NOT NULL,
    action      VARCHAR(60) NOT NULL,        -- 'ban_account', 'give_item'...
    target      VARCHAR(60) NULL,            -- conta/personagem alvo
    details     TEXT NULL,                   -- JSON com antes/depois
    ip          VARCHAR(45) NOT NULL,
    created_at  DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_admin (admin_id, created_at)
);

Autenticação forte e sessão

Nunca armazene senha em texto puro. Use password_hash() com bcrypt ou Argon2. No login, verifique com password_verify() e regenere a sessão para evitar fixation.

<?php
session_start();

function login(string $user, string $pass, PDO $db): bool {
    $stmt = $db->prepare("SELECT id, pass_hash, role, active, totp_secret
                          FROM admin_users WHERE username = ?");
    $stmt->execute([$user]);
    $u = $stmt->fetch(PDO::FETCH_ASSOC);

    if (!$u || !$u['active'] || !password_verify($pass, $u['pass_hash'])) {
        registrarTentativaFalha($user, $_SERVER['REMOTE_ADDR']);
        return false;
    }

    // se houver 2FA, exigir o código TOTP antes de concluir
    if ($u['totp_secret']) { $_SESSION['pending_2fa'] = $u['id']; return true; }

    session_regenerate_id(true);
    $_SESSION['admin_id'] = $u['id'];
    $_SESSION['role']     = $u['role'];
    return true;
}

Adote 2FA (TOTP) para todos os administradores — é a diferença entre um vazamento de senha ser um susto ou uma catástrofe. Aplique rate limiting no login (ex.: bloquear após 5 tentativas em 10 minutos por IP) para conter força bruta.

Controle de permissões (RBAC)

Cada rota do painel declara qual papel pode acessá-la. Centralize essa checagem em um middleware para não esquecer nenhuma rota.

<?php
function exigirPapel(array $permitidos): void {
    if (empty($_SESSION['admin_id']) || !in_array($_SESSION['role'], $permitidos, true)) {
        http_response_code(403);
        exit('Acesso negado');
    }
}

// no topo de uma rota sensível:
exigirPapel(['admin']);          // só admin
// ou
exigirPapel(['admin', 'gm']);    // admin e gm

Uma matriz de permissões deixa claro quem faz o quê. Ajuste conforme a confiança da sua equipe:

AçãoAdminGMSuporte
Ver contas e personagensSimSimSim
Banir / desbanirSimSimNão
Dar itens / zenSimSimNão
Editar resets / levelSimNãoNão
Gerenciar usuários do painelSimNãoNão
Ver logs de auditoriaSimNãoNão

Módulo de gestão de contas e personagens

O núcleo funcional do painel é consultar e editar contas. Sempre use consultas parametrizadas — concatenar string em SQL é a porta principal para SQL Injection, e num painel de admin isso é fatal.

<?php
// buscar conta com segurança (nomes de coluna VARIAM por versão)
function buscarConta(string $account, PDO $game): ?array {
    $stmt = $game->prepare(
        "SELECT memb___id, memb_name, mail_addr, bloc_code, ctl1_code
         FROM MEMB_INFO WHERE memb___id = ?"
    );
    $stmt->execute([$account]);
    return $stmt->fetch(PDO::FETCH_ASSOC) ?: null;
}

A tabela MEMB_INFO e as colunas bloc_code (bloqueio) e ctl1_code (tipo de conta/GM) são exemplos típicos de Season 6. Sua versão pode ter nomes e estruturas diferentes — confirme sempre.

Módulo de banimento

Banir normalmente significa marcar a conta como bloqueada. Registre a ação na auditoria e, se possível, o motivo e a duração.

<?php
function banirConta(string $account, string $motivo, PDO $game, PDO $site): void {
    exigirPapel(['admin', 'gm']);

    // estado anterior para o log
    $antes = buscarConta($account, $game);

    $game->prepare("UPDATE MEMB_INFO SET bloc_code = '1' WHERE memb___id = ?")
         ->execute([$account]);

    auditar($site, 'ban_account', $account, [
        'antes' => $antes['bloc_code'] ?? null,
        'depois' => '1',
        'motivo' => $motivo,
    ]);
}

Se o jogador estiver online, force a desconexão pelo mecanismo da sua versão (ou avise que o ban só surte efeito no próximo login), para ele não continuar jogando banido.

Módulo de envio de itens e zen

Este é o módulo mais perigoso do painel — é onde a economia pode ser quebrada. Duas armadilhas: duplicação (creditar duas vezes) e conflito com o jogador online (a mudança é sobrescrita quando o jogo salva o personagem). Boas práticas:

  1. Prefira aplicar com o jogador offline, ou use a fila oficial de "gift"/warehouse da sua distribuição, se existir.
  2. Torne a operação idempotente, com um identificador único por envio.
  3. Sempre audite valor, item e alvo.
<?php
function darZen(string $account, int $valor, PDO $game, PDO $site): void {
    exigirPapel(['admin', 'gm']);
    if ($valor <= 0 || $valor > 2000000000) throw new RuntimeException('valor inválido');

    // exemplo: creditar zen no warehouse da conta (coluna VARIA por versão)
    $game->prepare("UPDATE warehouse SET Money = Money + ? WHERE AccountID = ?")
         ->execute([$valor, $account]);

    auditar($site, 'give_zen', $account, ['valor' => $valor]);
}

Nunca construa a query com o valor concatenado, e valide limites máximos — um GM (ou um invasor com a sessão dele) não deveria conseguir dar bilhões sem trava.

Registrando a auditoria

A função de auditoria é chamada por todos os módulos. Ela é a sua caixa-preta.

<?php
function auditar(PDO $site, string $action, ?string $target, array $details): void {
    $stmt = $site->prepare(
        "INSERT INTO admin_audit (admin_id, action, target, details, ip)
         VALUES (?, ?, ?, ?, ?)"
    );
    $stmt->execute([
        $_SESSION['admin_id'] ?? 0,
        $action,
        $target,
        json_encode($details, JSON_UNESCAPED_UNICODE),
        $_SERVER['REMOTE_ADDR'],
    ]);
}

Trate o log como imutável: nenhuma rota do painel deve permitir editar ou apagar registros de auditoria. Se um GM abusar, é aqui que você prova. Considere replicar os logs para outro destino (arquivo ou banco separado) para o caso de o painel ser comprometido.

Front-end e usabilidade

Mantenha a interface simples e orientada a busca: um campo para localizar conta/personagem e ações claras com confirmação dupla nas operações destrutivas.

// confirmação dupla antes de banir
function confirmarBan(account) {
  if (confirm(`Banir a conta "${account}"? Esta ação será registrada.`)) {
    // envia POST com token CSRF ao backend
  }
}

Inclua sempre um token CSRF em cada formulário que altera estado, para impedir que um site malicioso force um admin logado a executar ações. Escape toda saída em HTML para evitar XSS (por exemplo, ao exibir nomes de personagem que vieram do banco). Se este painel faz parte de um servidor que você está montando agora, veja também o guia geral de como criar um servidor de MU Online para posicionar o painel na infraestrutura.

Erros comuns e soluções

SintomaCausa provávelSolução
Painel invadido / itens duplicadosSessão de admin sequestrada, sem 2FAAtive 2FA, restrinja IP, regenere sessão no login
SQL Injection no módulo de buscaQuery concatenada com entradaUse exclusivamente PDO parametrizado
Item some após dar para jogador onlinePersonagem salvo sobrescreveu a mudançaAplique com jogador offline ou via fila oficial
Não sei quem baniu um jogadorFalta de auditoriaRegistre toda ação em admin_audit
GM acessou área de adminRBAC não checado na rotaMiddleware exigirPapel em toda rota sensível
Força bruta no loginSem rate limitBloqueie por tentativas/IP e adicione 2FA
XSS ao exibir nome de charSaída não escapadaEscape HTML de todo dado vindo do banco

Segurança em profundidade — resumo prático

  • HTTPS obrigatório; painel em subdomínio próprio, com restrição de IP quando possível.
  • Senhas em bcrypt/Argon2; 2FA para todos os administradores.
  • RBAC checado em servidor, nunca só no front-end (esconder botão não é segurança).
  • Todo SQL parametrizado; toda saída escapada; token CSRF em formulários.
  • Banco do jogo isolado da internet — só o painel fala com ele.
  • Auditoria imutável de todas as ações sensíveis, com replicação externa.
  • Limites de valor em operações econômicas (zen, itens) para conter abuso.

Checklist de lançamento

  • Painel servido apenas via HTTPS, em subdomínio protegido
  • Tabelas admin_users e admin_audit criadas
  • Senhas em hash forte e 2FA ativo para admins
  • Rate limiting no login implementado
  • Middleware de RBAC aplicado em todas as rotas sensíveis
  • Todas as queries parametrizadas (revisão manual feita)
  • Token CSRF em todos os formulários de escrita
  • Nomes reais de tabela/coluna do game DB confirmados para sua versão
  • Módulo de itens/zen com limite e idempotência testado
  • Auditoria gravando quem/o quê/quando/onde em cada ação
  • Banco do jogo inacessível pela internet (firewall verificado)
  • Teste de invasão básico feito (injection, XSS, escalada de papel)

Com um painel bem construído, você deixa de mexer no banco na mão, delega tarefas à sua equipe com segurança, responde a incidentes com logs reais e protege o ativo mais valioso do servidor: a confiança dos jogadores. Construa camada por camada, teste cada barreira e trate o painel sempre como se ele já estivesse sob ataque — porque, mais cedo ou mais tarde, ele estará.

Perguntas frequentes

Preciso de um painel web ou o Navicat resolve?

Editar direto no banco funciona no início, mas é arriscado e não deixa rastro. Um painel web dá controle de permissões, validações, logs de auditoria e permite delegar tarefas a GMs sem entregar acesso total ao banco.

Qual linguagem usar para o painel de administração?

PHP com PDO é o mais comum no mundo MU por rodar no mesmo ambiente do site, mas você pode usar Node.js, Python ou .NET. O importante é conectar com segurança ao SQL Server do jogo e nunca expor o banco à internet.

Como proteger o painel de acesso não autorizado?

Use autenticação forte com senha em hash, 2FA para administradores, restrição por IP, HTTPS obrigatório, controle de permissões por papel e registro de auditoria de todas as ações sensíveis.

É seguro dar itens e zen pelo painel enquanto o jogador está online?

É arriscado. Alterações no personagem enquanto ele está logado podem ser sobrescritas quando o jogo salva, ou causar duplicação. O ideal é aplicar mudanças com o jogador offline ou usar a fila oficial de warehouse/gift da sua versão.

Como saber quem fez cada alteração no painel?

Com uma tabela de auditoria que registra usuário admin, ação, alvo, dados antes/depois, IP e horário. Sem log de auditoria você não consegue investigar abuso de GM nem reverter erros.

GA
Editor de guias e builds

Gabriel cobre gameplay, builds de classes, PvP e progressão. Testa cada estratégia em servidor antes de publicar.

Continue lendo

Artigos relacionados