cibertest / index.html
doctorlinux's picture
Upload index.html
4c98cea verified
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Autoevaluación de Ciberseguridad Operativa - Doctor Linux</title>
<style>
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Inter,Arial,sans-serif;background:#f5f6f5;margin:0;padding:0}
.dlx-wrap{max-width:960px;margin:auto;padding:16px}
.dlx-card{background:#fff;border:1px solid #e6ebef;border-radius:16px;box-shadow:0 6px 24px rgba(0,0,0,.06);padding:22px;margin:14px 0}
.dlx-title{font-size:28px;margin:0 0 4px;color:#214424}
.dlx-sub{color:#5c6b5f;margin-bottom:16px}
.dlx-progress{height:10px;background:#eff4f0;border-radius:999px;overflow:hidden;margin:10px 0 18px}
.dlx-bar{height:100%;width:0;background:#7fbf7f;transition:width .3s}
.dlx-q h4{margin:0 0 6px;font-size:18px;display:flex;align-items:flex-start;gap:8px}
.dlx-options{display:flex;gap:10px;flex-wrap:wrap;margin:6px 0 12px}
.dlx-pill{border:1px solid #d7e1d9;padding:8px 12px;border-radius:999px;cursor:pointer}
.dlx-pill input{display:none}
.dlx-pill.active{background:#214424;color:#fff;border-color:#214424}
.dlx-nav{display:flex;gap:10px;justify-content:space-between;margin-top:8px}
.dlx-btn{background:#214424;color:#fff;border:none;border-radius:10px;padding:12px 16px;cursor:pointer;transition:all 0.3s}
.dlx-btn:hover{background:#1a361c}
.dlx-btn[disabled]{opacity:.5;cursor:not-allowed}
.dlx-meter{display:grid;grid-template-columns:1fr auto;gap:6px 10px;margin:8px 0}
.dlx-badge{font-weight:600}
.dlx-tag{display:inline-block;background:#eff4f0;border:1px solid #dfe9e2;border-radius:8px;padding:6px 10px;margin:6px 6px 0 0}
.dlx-note{color:#6a786d}
.dlx-score{font-size:40px;font-weight:800;color:#214424}
.dlx-muted{color:#7b8b7f}
/* Estilos para el botón de ayuda */
.help-btn {
background: #214424;
color: white;
border: none;
border-radius: 50%;
width: 22px;
height: 22px;
font-size: 12px;
font-weight: bold;
cursor: help;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
margin-top: 2px;
}
.help-btn:hover {
background: #1a361c;
transform: scale(1.1);
}
/* Modal de ayuda */
.help-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1000;
justify-content: center;
align-items: center;
}
.help-content {
background: #fff;
padding: 24px;
border-radius: 16px;
width: 90%;
max-width: 500px;
border: 2px solid #214424;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 20px 60px rgba(0,0,0,0.2);
}
.help-content h4 {
margin: 0 0 16px 0;
color: #214424;
font-size: 20px;
border-bottom: 2px solid #eff4f0;
padding-bottom: 8px;
}
.help-content .close-btn {
background: #214424;
color: white;
border: none;
padding: 10px 20px;
border-radius: 10px;
cursor: pointer;
margin-top: 16px;
font-weight: 600;
}
.help-content .close-btn:hover {
background: #1a361c;
}
.help-example {
background: #f8f9f8;
border-left: 4px solid #214424;
padding: 12px 16px;
margin: 12px 0;
border-radius: 0 8px 8px 0;
}
.help-example h5 {
margin: 0 0 8px 0;
color: #214424;
font-size: 14px;
}
.help-example code {
background: #e9efe9;
padding: 4px 8px;
border-radius: 4px;
font-family: monospace;
font-size: 12px;
}
</style>
</head>
<body>
<div class="dlx-wrap" id="dlxApp">
<div class="dlx-card">
<h2 class="dlx-title">Autoevaluación de Ciberseguridad Operativa</h2>
<div class="dlx-sub">Responde con honestidad. Obtendrás tu <b>puntaje</b>, los <b>riesgos clave</b> y un plan sugerido de mejora.</div>
<div class="dlx-progress"><div class="dlx-bar" id="dlxBar"></div></div>
<div class="dlx-note dlx-muted" id="dlxStepNote"></div>
</div>
<div id="dlxSteps"></div>
<div class="dlx-card" id="dlxNavBox">
<div class="dlx-nav">
<button class="dlx-btn" id="prevBtn">← Anterior</button>
<button class="dlx-btn" id="nextBtn">Siguiente →</button>
</div>
</div>
<div class="dlx-card" id="dlxResult" style="display:none">
<h3 class="dlx-title">Tu diagnóstico</h3>
<div class="dlx-sub">Este resultado es orientativo. Si quieres un informe firmado por ingeniería, solicita el <b>diagnóstico gratuito</b>.</div>
<div style="display:flex;gap:24px;align-items:center;flex-wrap:wrap">
<div>
<div class="dlx-muted">Puntaje global</div>
<div class="dlx-score" id="dlxScore">—%</div>
<div class="dlx-tag" id="dlxLabel"></div>
</div>
<div style="flex:1;min-width:260px">
<div class="dlx-progress"><div class="dlx-bar" id="dlxBarFinal" style="background:#3aa655"></div></div>
<div class="dlx-note">≈ Mayor a 80%: postura sólida. 60–79%: revisar. Menor a 60%: riesgo elevado.</div>
</div>
</div>
<div class="dlx-card" style="margin-top:16px">
<h4 style="margin:0 0 8px">Detalle por dominio</h4>
<div id="dlxBreakdown" class="dlx-meter"></div>
</div>
<div class="dlx-card">
<h4 style="margin:0 0 8px">Recomendaciones inmediatas</h4>
<div id="dlxRecs"></div>
<div class="dlx-note" style="margin-top:8px">Tip: prioriza los dominios con menor puntaje. Podemos ayudarte a cerrar brechas con <b>hardening, firewalls, backups 3-2-1 y monitoreo 24/7</b>.</div>
</div>
<!-- BOTONES DE ACCIÓN -->
<div class="dlx-nav" style="margin-top:25px">
<button class="dlx-btn" onclick="window.location.reload()">🔄 Nueva Evaluación</button>
<button class="dlx-btn" id="analyzeBtn">🤖 Análisis con IA</button>
<button class="dlx-btn" onclick="downloadReport()" style="background:#3aa655">📄 Descargar Informe</button>
</div>
<div id="iaBox" class="dlx-card" style="display:none;margin-top:16px">
<h4>Análisis generado por IA</h4>
<pre id="iaOutput" style="white-space:pre-wrap;"></pre>
</div>
</div>
</div>
<!-- Modal de ayuda -->
<div id="helpModal" class="help-modal">
<div class="help-content">
<h4 id="helpTitle">Ayuda</h4>
<div id="helpText"></div>
<button class="close-btn" id="closeHelp">Cerrar</button>
</div>
</div>
<script>
/* === CONFIGURACIÓN INICIAL === */
const DOMAINS = [
{ id:'perimetro', name:'Perímetro / Firewall', qs:[
{q:'¿Usas un firewall dedicado (Mikrotik/OPNsense/etc.) con reglas mínimas por servicio?', help:'Un firewall dedicado es un dispositivo/software que filtra todo el tráfico entre tu red e Internet. "Reglas mínimas" significa permitir SOLO los puertos y servicios estrictamente necesarios para operar, denegando todo lo demás por defecto.'},
{q:'¿Tienes listas de acceso/geo-bloqueo/IPS/DoS activas?', help:'Listas de acceso: Bloquean IPs maliciosas conocidas. Geo-bloqueo: Restringe tráfico de países de alto riesgo. IPS: Detecta y bloquea patrones de ataque en tiempo real. Protección DoS: Limita conexiones para prevenir saturación.'},
{q:'¿Los servicios expuestos están detrás de NAT o Port-Forward controlado?', help:'NAT oculta las IPs internas de tu red. Port-Forward controlado significa redirigir SOLO puertos específicos necesarios (ej: puerto 443 para web), no rangos completos.'},
{q:'¿Hay políticas VPN de acceso remoto con 2FA?', help:'VPN crea un túnel seguro para acceso remoto. 2FA (autenticación de dos factores) añade una capa extra de seguridad además de la contraseña (código SMS, app authenticator, etc.).'}
]},
{ id:'servers', name:'Servidores / Hardening', qs:[
{q:'¿Cuentas con hardening básico (SSH seguro, usuarios/roles, auditoría)?', help:'Hardening significa configurar el sistema de forma segura: SSH sin acceso root, solo autenticación por claves, usuarios con privilegios mínimos, y logs de auditoría activos.'},
{q:'¿Actualizaciones y parches aplicados regularmente?', help:'Aplicar actualizaciones de seguridad mensualmente para corregir vulnerabilidades conocidas en sistema operativo y aplicaciones.'},
{q:'¿Servicios innecesarios deshabilitados/controlados?', help:'Cada servicio activo es una posible puerta de entrada. Deshabilitar servicios como FTP, Telnet, servicios de impresión no usados, etc.'}
]},
{ id:'backups', name:'Backups y Recuperación', qs:[
{q:'¿Aplicas la regla 3-2-1 (3 copias, 2 medios, 1 offsite)?', help:'3 copias totales de datos, en al menos 2 medios diferentes (discos, cinta, cloud), y 1 copia fuera del sitio físico principal.'},
{q:'¿Pruebas de restauración realizadas en los últimos 6 meses?', help:'Verificar periódicamente que los backups son recuperables restaurando datos de prueba en ambiente controlado.'},
{q:'¿Backups protegidos contra ransomware (inmutables/air-gap)?', help:'Backups inmutables no pueden ser modificados o eliminados. Air-gap significa almacenamiento físicamente desconectado de la red.'}
]},
{ id:'monitor', name:'Monitoreo y Alertas', qs:[
{q:'¿Monitoreo centralizado (Zabbix/PRTG/Grafana) con alertas 24/7?', help:'Sistema que monitorea servidores, redes, servicios y envía alertas inmediatas cuando detecta problemas o anomalías.'},
{q:'¿Métricas revisadas mensualmente?', help:'Analizar regularmente rendimiento, capacidad, intentos de acceso fallidos, y otros indicadores de seguridad.'},
{q:'¿Alertas integradas con soporte?', help:'Las alertas críticas deben notificar automáticamente al personal técnico mediante email, SMS, Telegram, etc.'}
]},
{ id:'network', name:'Red y Conectividad', qs:[
{q:'¿Segmentación VLANs para aislar servicios críticos?', help:'Dividir la red en segmentos lógicos separados para aislar servidores críticos, usuarios, e invitados.'},
{q:'¿Control de ancho de banda/Proxy/filtrado de contenidos?', help:'Limitar ancho de banda por servicio, filtrar contenido malicioso, y controlar acceso a internet mediante proxy.'},
{q:'¿Wi-Fi empresarial con WPA2-Enterprise?', help:'WPA2-Enterprise usa autenticación individual por usuario en lugar de contraseña compartida para toda la red WiFi.'}
]},
{ id:'endpoints', name:'Usuarios / Estaciones', qs:[
{q:'¿Antimalware/EDR y políticas de actualización?', help:'EDR detecta comportamientos sospechosos. Políticas de actualización automática para software y antivirus.'},
{q:'¿Gestión de contraseñas y MFA?', help:'Password manager para contraseñas seguras y únicas. MFA requiere código adicional además de la contraseña.'},
{q:'¿Políticas de mínimo privilegio + bloqueo de USB?', help:'Usuarios solo tienen permisos necesarios para su trabajo. Bloqueo de puertos USB previene infecciones y fugas.'}
]},
{ id:'webmail', name:'Web y Correo', qs:[
{q:'¿Sitios con HTTPS válido y cabeceras seguras?', help:'HTTPS encripta comunicación web. Cabeceras de seguridad previenen ataques como XSS, clickjacking, etc.'},
{q:'¿Correo con SPF, DKIM y DMARC publicados?', help:'Protocolos que previenen suplantación de identidad (spoofing) en correos electrónicos.'},
{q:'¿WAF/antispam/antiphishing activos?', help:'WAF protege aplicaciones web, antispam filtra correo no deseado, antiphishing detecta intentos de engaño.'}
]}
];
const SCALE = [
{label:'No',score:0},
{label:'Parcial',score:50},
{label:'Sí',score:100},
{label:'No sé',score:null}
];
const RECS = {
perimetro:'Endurecer perímetro: reglas mínimo necesario, VPN 2FA, IDS/IPS y protección DoS.',
servers:'Aplicar hardening, cuentas/roles y mantener parches al día.',
backups:'Implementar 3-2-1 con pruebas de restauración y backups inmutables.',
monitor:'Centralizar monitoreo (Zabbix/PRTG) y definir umbrales.',
network:'Segregar VLANs, reforzar proxy y aislar Wi-Fi invitados.',
endpoints:'Mínimo privilegio, EDR/antimalware y MFA.',
webmail:'Forzar HTTPS, cabeceras OWASP, SPF+DKIM+DMARC y WAF.'
};
let current = 0, answers = {};
const steps = document.getElementById('dlxSteps'),
bar = document.getElementById('dlxBar'),
note = document.getElementById('dlxStepNote'),
prev = document.getElementById('prevBtn'),
next = document.getElementById('nextBtn'),
result = document.getElementById('dlxResult'),
nav = document.getElementById('dlxNavBox');
/* === SISTEMA DE AYUDA === */
function showHelp(helpKey, questionText) {
const modal = document.getElementById('helpModal');
const title = document.getElementById('helpTitle');
const content = document.getElementById('helpText');
// Encontrar la pregunta correspondiente para mostrar su ayuda
let helpContent = '';
DOMAINS.forEach(domain => {
domain.qs.forEach((item, i) => {
const currentHelpKey = `${domain.id}-q${i}`;
if (currentHelpKey === helpKey) {
helpContent = item.help;
}
});
});
if (helpContent) {
content.innerHTML = `
<h4>💡 Explicación Técnica</h4>
<p><strong>Pregunta:</strong> ${questionText}</p>
<div class="help-example">
<h5>🔍 Qué significa esto:</h5>
<p>${helpContent}</p>
</div>
<div class="help-example">
<h5>🎯 Por qué es importante:</h5>
<p>Esta medida protege contra amenazas específicas y es considerada una práctica esencial de seguridad.</p>
</div>
`;
} else {
content.innerHTML = `
<h4>💡 Ayuda Contextual</h4>
<p><strong>Pregunta:</strong> ${questionText}</p>
<p>Esta pregunta evalúa la implementación de controles de seguridad específicos para este dominio técnico.</p>
`;
}
modal.style.display = 'flex';
}
function closeHelp() {
document.getElementById('helpModal').style.display = 'none';
}
// Event listeners para el modal de ayuda
document.getElementById('closeHelp').addEventListener('click', closeHelp);
document.getElementById('helpModal').addEventListener('click', function(e) {
if (e.target.id === 'helpModal') closeHelp();
});
/* === FUNCIONES PRINCIPALES === */
function render() {
steps.innerHTML = '';
const d = DOMAINS[current];
note.innerHTML = `<b>${current+1}/${DOMAINS.length}</b> · ${d.name}`;
const card = document.createElement('div');
card.className = 'dlx-card';
card.innerHTML = `<h3 class="dlx-title">${d.name}</h3>`;
d.qs.forEach((item, i) => {
const b = document.createElement('div');
b.className = 'dlx-q';
// Crear botón de ayuda con ID único
const helpKey = `${d.id}-q${i}`;
const helpBtn = `<button class="help-btn" onclick="showHelp('${helpKey}', '${item.q.replace(/'/g, "\\'")}')">?</button>`;
b.innerHTML = `<h4>${item.q} ${helpBtn}</h4>`;
const row = document.createElement('div');
row.className = 'dlx-options';
SCALE.forEach(opt => {
const lbl = document.createElement('label');
lbl.className = 'dlx-pill';
lbl.textContent = opt.label;
lbl.onclick = () => {
row.querySelectorAll('.dlx-pill').forEach(p => p.classList.remove('active'));
lbl.classList.add('active');
if (!answers[d.id]) answers[d.id] = [];
answers[d.id][i] = opt.score;
updateButtons();
};
if (answers[d.id] && answers[d.id][i] === opt.score) lbl.classList.add('active');
row.appendChild(lbl);
});
b.appendChild(row);
card.appendChild(b);
});
steps.appendChild(card);
bar.style.width = Math.round(current / DOMAINS.length * 100) + '%';
updateButtons();
}
function allAnswered(i) {
const d = DOMAINS[i];
return answers[d.id] && answers[d.id].length === d.qs.length && answers[d.id].every(v => v !== undefined);
}
function avg(a) {
const nums = a.filter(v => typeof v === 'number' && isFinite(v));
if (nums.length === 0) return 0;
return nums.reduce((x, y) => x + y, 0) / nums.length;
}
function updateButtons() {
prev.disabled = current === 0;
const last = current === DOMAINS.length - 1;
next.textContent = last ? 'Ver resultado →' : 'Siguiente →';
next.disabled = !allAnswered(current);
}
prev.onclick = () => { if (current > 0) { current--; render(); } };
next.onclick = () => {
if (current < DOMAINS.length - 1) {
if (!allAnswered(current)) return;
current++; render();
} else {
if (!allAnswered(current)) return;
showResult();
}
};
function showResult() {
bar.style.width = '100%';
nav.style.display = 'none';
steps.style.display = 'none';
note.style.display = 'none';
result.style.display = 'block';
let weighted = 0, total = 0;
const breakdown = document.getElementById('dlxBreakdown'),
recs = document.getElementById('dlxRecs');
breakdown.innerHTML = '';
recs.innerHTML = '';
DOMAINS.forEach(d => {
const a = answers[d.id] ? avg(answers[d.id]) : 0;
weighted += a; total += 100;
const pct = Math.round(a);
breakdown.innerHTML += `<div>${d.name}</div><div><b>${pct}%</b></div>`;
if (pct < 75) { recs.innerHTML += `<div class="dlx-tag">• ${RECS[d.id]}</div>`; }
});
const global = Math.round(weighted / DOMAINS.length);
document.getElementById('dlxScore').textContent = global + '%';
document.getElementById('dlxBarFinal').style.width = global + '%';
const label = document.getElementById('dlxLabel');
if (global >= 80) { label.textContent = 'Nivel Sólido'; label.style.background = '#e7f7e7'; }
else if (global >= 60) { label.textContent = 'Nivel Medio (revisar)'; label.style.background = '#fff6e1'; }
else { label.textContent = 'Riesgo Alto'; label.style.background = '#ffe9e9'; }
// Guardar datos para el análisis IA
window.finalData = {
overall: global,
domains: DOMAINS.map(d => ({
name: d.name,
score: Math.round(avg(answers[d.id]))
}))
};
}
/* === DESCARGAR INFORME MEJORADO === */
function downloadReport() {
const global = window.finalData.overall;
const date = new Date().toLocaleDateString('es-ES');
// Crear contenido con formato profesional
const content = `
╔══════════════════════════════════════════════════╗
║ INFORME DE CIBERSEGURIDAD ║
║ DOCTOR LINUX ║
╚══════════════════════════════════════════════════╝
📅 Fecha de evaluación: ${date}
🎯 Puntaje Global: ${global}%
${global >= 80 ? '✅ POSTURA SÓLIDA - Controles robustos implementados' :
global >= 60 ? '⚠️ MEJORAS NECESARIAS - Se requieren ajustes en controles' :
'🚨 RIESGO ELEVADO - Atención inmediata requerida'}
📊 DETALLE POR DOMINIO TÉCNICO:
${window.finalData.domains.map(d => {
const icon = d.score >= 80 ? '✅' : d.score >= 60 ? '⚠️ ' : '🚨';
return `${icon} ${d.name}: ${d.score}%`;
}).join('\n')}
🛠️ RECOMENDACIONES PRIORITARIAS:
1. Revisar y endurecer configuración de firewall
2. Implementar estrategia de backups 3-2-1 con pruebas
3. Establecer monitoreo centralizado 24/7
4. Aplicar hardening en servidores y estaciones
5. Implementar autenticación multifactor (MFA)
📈 PLAN DE ACCIÓN SUGERIDO:
• SEMANA 1: Contención de riesgos críticos
• SEMANA 2-4: Implementación controles básicos
• MES 2-3: Mejora de madurez operacional
• MES 4-6: Optimización y automatización
──────────────────────────────────────────────────
Este es un informe automático generado por la
herramienta de autodiagnóstico de Doctor Linux.
Para un análisis técnico detallado y personalizado,
contacte a nuestros especialistas:
🌐 www.doctorlinux.com
📧 gerencia@doctorlinux.com
📞 +57 315 340 7238
──────────────────────────────────────────────────
`;
// Crear y descargar archivo
const blob = new Blob([content], { type: 'text/plain; charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `informe-ciberseguridad-doctor-linux-${date.replace(/\//g, '-')}.txt`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
/* === ANÁLISIS CON IA === */
document.getElementById('analyzeBtn').onclick = async function() {
const box = document.getElementById('iaBox');
const out = document.getElementById('iaOutput');
const btn = this;
box.style.display = 'block';
out.textContent = 'Generando análisis detallado...';
btn.disabled = true;
try {
const res = await fetch('/analyze', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(window.finalData)
});
if (res.ok) {
const data = await res.json();
out.textContent = data.analysis || 'Análisis completado.';
} else {
throw new Error('Error del servidor');
}
} catch (error) {
out.textContent = 'El análisis detallado no está disponible en este momento.\n\nPuntaje: ' + window.finalData.overall + '%\n\nPara un diagnóstico completo, contacta a Doctor Linux.';
} finally {
btn.disabled = false;
}
};
// Inicializar aplicación
render();
</script>
</body>
</html>