El mayor portal de MU Online de Brasil — desde 2003
Tutorial Avanzado Infra

Cómo proteger el panel administrativo de tu servidor de MU Online con autenticación en dos pasos (2FA)

Implementa autenticación en dos pasos (2FA) basada en TOTP en el panel administrativo PHP de tu servidor de MU Online, con generación de secreto, código QR, verificación de código y un plan de recuperación de acceso en caso de que el jugador pierda el dispositivo.

BR Bruno · Actualizado el 28 jul 2024 · ⏱ 15 min de lectura
Respuesta rápida

El panel administrativo de un servidor de MU Online es el blanco más valioso para un atacante: una sola cuenta comprometida con nivel de Administrador puede generar ítems, alterar saldos, banear jugadores o derribar la base de datos entera. Proteger ese acceso solo con contraseña — aunque sea una co

El panel administrativo de un servidor de MU Online es el blanco más valioso para un atacante: una sola cuenta comprometida con nivel de Administrador puede generar ítems, alterar saldos, banear jugadores o derribar la base de datos entera. Proteger ese acceso solo con contraseña — aunque sea una contraseña fuerte — deja al servidor vulnerable al phishing, a la reutilización de contraseñas filtradas en otro sitio y a los keyloggers. La autenticación en dos pasos (2FA) basada en TOTP añade una segunda barrera que un atacante no puede reproducir solo con la contraseña robada. Este tutorial muestra cómo implementar el 2FA en el panel PHP legado del servidor, desde el lado de la base de datos hasta la pantalla de verificación del jugador.

Por qué la contraseña sola no es suficiente

Las contraseñas se filtran por varios caminos que no dependen de qué tan fuerte sea la contraseña en sí: reutilización de la misma contraseña en otro sitio que sufrió una filtración, phishing disfrazado de una página de login idéntica, o malware tipo keylogger en la máquina del administrador. En cualquiera de estos casos, el atacante obtiene la contraseña correcta y pasa la autenticación con normalidad. El 2FA rompe ese escenario porque exige un segundo factor — algo que el administrador tiene (el código generado en el celular), no solo algo que sabe (la contraseña).

Cómo funciona el TOTP (Time-based One-Time Password)

El TOTP genera un código numérico de 6 dígitos que cambia cada 30 segundos, calculado a partir de un secreto compartido entre el servidor y la aplicación autenticadora (Google Authenticator, Authy, Microsoft Authenticator) y de la hora actual. El servidor y el celular nunca intercambian ese código por la red en el momento de la generación — ambos calculan el mismo valor de forma independiente, lo que hace que el método sea resistente a la interceptación de red.

ComponenteRol
Secreto compartido (secret)Generado una vez, almacenado en la base de datos y en la app del usuario
Timestamp actualSincronizado entre servidor y dispositivo (ventana de 30s)
Algoritmo HMAC-SHA1 (RFC 6238)Combina secreto + timestamp para generar el código de 6 dígitos
Ventana de toleranciaAcepta el código del intervalo anterior/siguiente para tolerar una pequeña diferencia de reloj

Paso 1 — Preparar la tabla de secretos en la base de datos

Agrega una columna para almacenar el secreto TOTP de cada cuenta administrativa, y una tabla separada para los códigos de recuperación:

ALTER TABLE admin_accounts ADD COLUMN totp_secret VARCHAR(64) NULL;
ALTER TABLE admin_accounts ADD COLUMN totp_enabled TINYINT(1) NOT NULL DEFAULT 0;

CREATE TABLE admin_recovery_codes (
    id INT AUTO_INCREMENT PRIMARY KEY,
    admin_id INT NOT NULL,
    code_hash VARCHAR(255) NOT NULL,
    used TINYINT(1) NOT NULL DEFAULT 0,
    FOREIGN KEY (admin_id) REFERENCES admin_accounts(id)
);

Nunca almacenes el secreto TOTP en texto plano accesible públicamente, y nunca almacenes los códigos de recuperación sin hash — trátalos como contraseñas de un solo uso.

Paso 2 — Instalar una biblioteca TOTP en PHP

Usa una biblioteca open source consolidada en lugar de implementar el algoritmo desde cero:

composer require spomky-labs/otphp

Esto evita errores sutiles de implementación del RFC 6238 que podrían generar códigos incompatibles con las aplicaciones autenticadoras estándar del mercado.

Paso 3 — Generar el secreto y el código QR de activación

use OTPHP\TOTP;

$totp = TOTP::generate();
$totp->setLabel('PainelAdmin-ViciadosMU');
$totp->setIssuer('ViciadosMU');

$secret = $totp->getSecret();
// Guardar $secret (cifrado) en la columna totp_secret del admin conectado

$qrCodeUrl = $totp->getQrCodeUri(
    'https://api.qrserver.com/v1/create-qr-code/?size=300x300&data=[DATA]',
    '[DATA]'
);
// Mostrar $qrCodeUrl en pantalla para que el admin lo escanee con la app autenticadora

Muestra el código QR solo una vez, en la pantalla de activación, y nunca registres el secreto en el log de la aplicación — es equivalente a una contraseña maestra del segundo factor.

Paso 4 — Verificar el código en la activación antes de confirmar

Antes de marcar totp_enabled = 1, exige que el administrador ingrese el código generado por la app, confirmando que el código QR se escaneó correctamente:

$codigoDigitado = $_POST['codigo'];

if ($totp->verify($codigoDigitado)) {
    // Activar totp_enabled = 1 en la base de datos
    // Generar y mostrar los códigos de recuperación (una única vez)
} else {
    // Error: código inválido, no activar todavía
}

Este paso evita el escenario en que el administrador cree que activó el 2FA, pero la app no se configuró correctamente, y queda bloqueado en el siguiente inicio de sesión.

Paso 5 — Generar y mostrar códigos de recuperación

En el momento de la activación exitosa, genera de 8 a 10 códigos de un solo uso y muéstralos solo una vez, indicándole al administrador que los guarde fuera de línea:

function gerarCodigosRecuperacao(int $quantidade = 10): array {
    $codigos = [];
    for ($i = 0; $i < $quantidade; $i++) {
        $codigos[] = strtoupper(bin2hex(random_bytes(4))); // ej: A1B2C3D4
    }
    return $codigos;
}

// Guardar solo el hash de cada código en la tabla admin_recovery_codes
foreach ($codigos as $codigo) {
    $hash = password_hash($codigo, PASSWORD_BCRYPT);
    // INSERT INTO admin_recovery_codes (admin_id, code_hash) VALUES (?, ?)
}

Paso 6 — Exigir el segundo factor en el inicio de sesión

En el flujo de login, después de validar correctamente la contraseña, muestra la pantalla de código TOTP antes de conceder la sesión administrativa completa:

if ($senhaValida) {
    if ($admin['totp_enabled']) {
        // Redirigir a la pantalla de verificación de código,
        // sin conceder todavía la sesión de nivel administrativo
        $_SESSION['pending_2fa_admin_id'] = $admin['id'];
    } else {
        // Conceder la sesión normalmente (o forzar la activación del 2FA, si es obligatorio)
    }
}
// En la pantalla de verificación
$codigo = $_POST['codigo'];
$totp = TOTP::createFromSecret($segredoDoBanco);

if ($totp->verify($codigo)) {
    // Conceder sesión administrativa completa
} else {
    // Verificar si es un código de recuperación válido (coincidencia de hash y used = 0)
    // Caso contrario, negar el acceso y registrar el intento
}

Paso 7 — Definir la política de obligatoriedad por nivel de cuenta

No todas las cuentas necesitan el mismo rigor. Define la política según el riesgo del nivel de acceso:

Nivel de cuenta¿2FA obligatorio?Justificación
OwnerAcceso total, mayor daño posible si se compromete
AdministradorComandos sensibles (additem, setmoney, ban)
Moderador de eventoRecomendadoAcceso limitado, pero aún distribuye ítems
Soporte juniorOpcionalComandos de menor impacto económico
Cuenta de jugador comúnOpcional/incentivadoProtección de cuenta personal, no administrativa

Paso 8 — Plan de recuperación sin comprometer la seguridad

Cuando un administrador pierde el dispositivo y no tiene los códigos de recuperación, define un proceso manual y documentado en lugar de simplemente desactivar el 2FA a partir de un pedido informal en Discord:

  1. Exige verificación de identidad fuera de banda (videollamada con otro administrador de confianza, o confirmación por correo registrado previamente).
  2. Un segundo administrador (nunca el propio solicitante) resetea totp_enabled = 0 directamente en la base de datos.
  3. Fuerza la reactivación del 2FA de inmediato en el próximo inicio de sesión.
  4. Registra el incidente en el log interno, incluyendo quién autorizó el reseteo.

Errores comunes y soluciones

SíntomaCausa probableSolución
El código de la app no coincide con el servidorReloj del celular o servidor desincronizadoSincronizar NTP en el servidor y verificar la hora del celular
El admin perdió el acceso y no tiene códigos de recuperaciónCódigos no generados o no guardados en la activaciónImplementar un proceso manual de reseteo con verificación cruzada
Secreto TOTP expuesto en el log de la aplicaciónDebug/log registrando una variable sensibleEliminar el log de variables de secreto y rotar los secretos expuestos
El 2FA está activado pero la sesión nunca pide el segundo factorEl flujo de login no verifica totp_enabled correctamenteRevisar la lógica de sesión pendiente antes de conceder acceso completo
Reseteo de 2FA hecho sin verificación de identidadFalta de proceso documentado de recuperaciónFormalizar el proceso con un segundo administrador obligatorio

Lista de verificación de implementación de 2FA en el panel

  • Tabla de secreto TOTP y códigos de recuperación creada en la base de datos.
  • Biblioteca TOTP confiable integrada (ej.: spomky-labs/otphp).
  • Flujo de activación con código QR y verificación de código antes de confirmar.
  • Códigos de recuperación generados, con hash y mostrados una única vez.
  • Inicio de sesión exigiendo el segundo factor antes de conceder sesión administrativa completa.
  • Política de obligatoriedad definida por nivel de cuenta.
  • Proceso documentado de recuperación de acceso con verificación cruzada.

Con el panel protegido por 2FA, revisa también los demás controles de acceso del equipo administrativo — la guía de creación de servidor de MU Online cubre la base de infraestructura sobre la que debe construirse esta capa extra de seguridad.

Preguntas frecuentes

¿El 2FA por SMS es lo suficientemente seguro para el panel de admin?

Es mejor que nada, pero el SMS es vulnerable al SIM swap y a la interceptación. Para cuentas de nivel Administrador y Owner, prefiere TOTP (Google Authenticator, Authy) o una llave física (FIDO2/WebAuthn), reservando el SMS como máximo como método secundario de recuperación.

¿Qué pasa si el administrador pierde el celular con el autenticador?

Por eso es esencial generar y almacenar códigos de recuperación (backup codes) en el momento de activar el 2FA, guardados en un lugar seguro fuera de línea. Sin esto, la única salida es un proceso manual de verificación de identidad para resetear el 2FA directamente en la base de datos.

¿El 2FA debe ser obligatorio para todos los niveles de cuenta del panel?

Se recomienda que sea obligatorio para los niveles con comandos administrativos sensibles (Admin, Owner) y opcional, pero incentivado, para cuentas comunes de jugador. Hacerlo obligatorio para todos de una vez puede generar fricción de soporte si la comunidad no está preparada.

¿El TOTP funciona sin internet en el celular del administrador?

Sí. El algoritmo TOTP genera el código localmente a partir del secreto compartido y la hora del dispositivo, sin necesitar conexión a internet en el momento de la generación — solo el reloj del celular necesita estar sincronizado correctamente.

¿Necesito una biblioteca paga para implementar TOTP en PHP?

No. Existen bibliotecas open source como spomky-labs/otphp o implementaciones simples del algoritmo RFC 6238 que pueden integrarse gratuitamente al panel PHP existente, sin depender de un servicio externo pago.

BR
Editor de eventos, mapas e ítems

Bruno es especialista en eventos, mapas, bosses y economía de ítems de MU Online. Documenta cada detalle basándose en el juego real.

Sigue leyendo

Artículos relacionados