Autor: ciberkaos

  • 1.5 – Objetos básicos en JavaScript

    1.5 – Objetos básicos en JavaScript

    En JavaScript existen objetos integrados que forman parte del núcleo del lenguaje. No necesitas crearlos: ya existen y puedes usarlos directamente.

    Los más importantes:

    • Math → cálculos matemáticos
    • Object → base de todos los objetos
    • Array → colecciones de datos
    • String → texto
    • Date → fechas y tiempo

    Acceso a propiedades y métodos

    Se usa el operador punto (.)

    Propiedad (dato)

    miObjeto.miPropiedad

    Método (acción)

    miObjeto.miMetodo(param1, param2)
    miObjeto.miMetodo()

    Objeto Math

    Sirve para realizar cálculos matemáticos. No se instancia.

    alert(Math.random());

    Genera número decimal entre 0 y 1

    letnumero=Math.floor(Math.random() *10);
    alert(numero);

    Métodos principales de Math

    MétodoQué haceEjemplo
    Math.random()Número aleatorio entre 0 y 1Math.random()
    Math.floor(n)Redondea hacia abajoMath.floor(4.9) → 4
    Math.ceil(n)Redondea hacia arribaMath.ceil(4.1) → 5
    Math.round(n)Redondeo normalMath.round(4.5) → 5
    Math.max(a,b)Mayor valorMath.max(5,10)
    Math.min(a,b)Menor valorMath.min(5,10)
    Math.pow(a,b)PotenciaMath.pow(2,3) → 8
    Math.sqrt(n)Raíz cuadradaMath.sqrt(16) → 4

    Objeto String

    Cuando creas texto, JavaScript crea un objeto String.

    let texto="Hola mundo";
    alert(texto.length);

    Métodos principales de String

    MétodoQué haceEjemplo
    lengthNúmero de caracteres"Hola".length → 4
    toUpperCase()Mayúsculas"hola".toUpperCase()
    toLowerCase()Minúsculas"HOLA".toLowerCase()
    includes(txt)Busca texto"JavaScript".includes("Script")
    indexOf(txt)Posición de texto"Hola".indexOf("o")
    substring(a,b)Extrae parte"Hola".substring(1,3)
    replace(a,b)Reemplaza"Hola".replace("o","0")
    trim()Quita espacios extremos" hola ".trim()

    Objeto Array

    Colecciones ordenadas de datos.

    let numeros= [10,20,30];
    numeros.push(40);

    Métodos principales de Array

    MétodoQué haceEjemplo
    lengthTamaño del array[1,2].length
    push(x)Añade al finalarr.push(5)
    pop()Elimina últimoarr.pop()
    shift()Elimina primeroarr.shift()
    unshift(x)Añade al inicioarr.unshift(0)
    includes(x)Comprueba existenciaarr.includes(10)
    indexOf(x)Posiciónarr.indexOf(20)
    join(sep)Convierte a textoarr.join(",")
    slice(a,b)Subarrayarr.slice(1,3)
    splice()Modifica arrayarr.splice(1,1)

    Objeto Object

    Es la base de todos los objetos en JavaScript.

    let persona= {nombre: "Ana",edad: 20};
    alert(persona.nombre);

    Métodos principales de Object

    MétodoQué haceEjemplo
    Object.keys(obj)Lista clavesObject.keys(persona)
    Object.values(obj)Lista valoresObject.values(persona)
    Object.entries(obj)Clave + valorObject.entries(persona)
    hasOwnProperty(k)Comprueba propiedadpersona.hasOwnProperty("edad")
    assign(a,b)Copia objetosObject.assign(a,b)

    Objeto Date

    El objeto Date representa fechas y tiempo. Internamente guarda milisegundos desde 1 enero 1970 (Unix Epoch).

    let ahora = new Date();
    alert(ahora);

    Crear fechas

    new Date()                      // Fecha actual
    new Date("2025-12-25")          // Desde texto
    new Date(2025, 0, 1)            // Año, mes(0-11), día

    Métodos principales de Date

    MétodoQué haceEjemplo
    getFullYear()Añofecha.getFullYear()
    getMonth()Mes (0-11)fecha.getMonth()
    getDate()Día del mesfecha.getDate()
    getDay()Día semana (0-6)fecha.getDay()
    getHours()Horafecha.getHours()
    getMinutes()Minutosfecha.getMinutes()
    getSeconds()Segundosfecha.getSeconds()
    getTime()Milisegundos desde 1970fecha.getTime()
    setFullYear(a)Cambia añofecha.setFullYear(2030)
    toLocaleDateString()Fecha formateadafecha.toLocaleDateString()
    toLocaleTimeString()Hora formateadafecha.toLocaleTimeString()

    Ejemplo práctico Date

    let ahora = new Date();
    
    let mensaje =
      "Hoy es: " + ahora.toLocaleDateString() +
      "\nHora: " + ahora.toLocaleTimeString();
    
    alert(mensaje);

    Concepto clave

    En JavaScript:

    • Las propiedades describen
    • Los métodos actúan

    Ejemplo:

    texto.length        → dato
    texto.toUpperCase() → acción
    fecha.getFullYear() → acción sobre el tiempo

    Otros objetos disponibles en JavaScript

    ObjetoQué esPara qué se usaEjemplo rápido
    NumberRepresenta númerosOperaciones numéricas, conversionesNumber("10")
    BooleanValores verdadero/falsoLógica condicionalBoolean(1)
    RegExpExpresiones regularesBuscar y validar texto/[a-z]+/.test("hola")
    JSONManejo de datos JSONConvertir objetos ↔ textoJSON.parse(txt)
    MapColección clave → valorEstructuras tipo diccionariomap.set("a",1)
    SetColección sin duplicadosListas únicasset.add(5)
    PromiseOperaciones asíncronasFetch, AJAX, temporizadoresfetch(url)
    FunctionFunciones como objetosProgramación funcionaltypeof f === "function"
    ErrorManejo de errorestry/catchthrow new Error()
    SymbolIdentificadores únicosPropiedades privadasSymbol("id")
    BigIntEnteros muy grandesCriptografía, cálculos grandes123n
    URLManipulación de URLsLeer parámetrosnew URL(location)
    FormDataDatos de formulariosEnvío POSTnew FormData(form)
    DateTiempo y fechasCalendario, relojesnew Date()
    MathMatemáticasCálculosMath.random()

    • JSON → traductor entre objetos y texto
    • Map vs Object → Map está optimizado para colecciones dinámicas
    • Set → evita duplicados automáticamente
    • Promise → permite esperar resultados sin bloquear el programa
    • RegExp → motor de búsqueda textual extremadamente potente
    • Symbol → claves invisibles para evitar colisiones
    • BigInt → números más allá del límite de Number

    Ejemplos

    JSON

    let texto = '{"nombre":"Ana"}';
    let obj = JSON.parse(texto);
    alert(obj.nombre);

    Map

    let mapa = new Map();
    mapa.set("usuario", "admin");
    alert(mapa.get("usuario"));

    Set

    let mapa = new Map();
    mapa.set("usuario", "admin");
    alert(mapa.get("usuario"));

    Promise (idea básica)

    fetch("datos.json")
      .then(r => r.json())
      .then(datos => console.log(datos));

    Ejercicios

    Ejercicio 1

    Mostrar un número aleatorio del 1 al 100.

    Ejercicio 2

    Crear un texto con tu nombre y mostrar:

    • Longitud
    • En mayúsculas
    • Si contiene la letra «a»

    Ejercicio 3

    Crear un array con 3 números y:

    • Añadir uno
    • Mostrar tamaño
    • Mostrar si contiene el número 5

    Ejercicio 4

    Mostrar:

    • Año actual
    • Mes actual
    • Hora actual
  • 1.6 – Arrays en JavaScript

    1.6 – Arrays en JavaScript

    Un array es una estructura que permite almacenar múltiples valores en una sola variable.

    Puede contener:

    • Números
    • Texto
    • Objetos
    • Otros arrays
    • Mezclas de todo (JavaScript no es quisquilloso)

    Crear un array

    let numeros= [10, 20, 30];

    También:

    letvacio= [];

    O usando el constructor:

    let lista=new Array(1,2,3);

    Acceder a elementos

    Los arrays empiezan en índice 0 (como casi todo en informática).

    let colores = ["rojo", "verde", "azul"];
    
    alert(colores[0]); // rojo
    alert(colores[2]); // azul

    Propiedad fundamental

    let numeros = [1,2,3,4];
    alert(numeros.length);

    length → número de elementos


    Métodos principales de Array

    Añadir y eliminar

    let lista = [10,20];
    
    lista.push(30);   // añade al final
    lista.pop();      // elimina último
    lista.unshift(5); // añade al inicio
    lista.shift();    // elimina primero

    Buscar elementos

    let numeros = [10,20,30];
    
    numeros.includes(20); // true
    numeros.indexOf(30);  // 2

    Convertir a texto

    let colores = ["rojo","verde","azul"];
    alert(colores.join(" - "));

    Resultado:

    rojo - verde - azul

    Extraer partes

    let datos = [1,2,3,4,5];
    
    let sub = datos.slice(1,4); // [2,3,4]

    slice no modifica el original.


    Modificar el array

    let datos = [1,2,3,4];
    
    datos.splice(1,2); // elimina desde posición 1 → elimina 2 elementos

    Resultado:

    [1,4]

    Video Arrays

    Tabla completa de métodos importantes

    MétodoQué haceEjemplo
    lengthTamaño del array[1,2].length
    push(x)Añade al finalarr.push(5)
    pop()Elimina últimoarr.pop()
    shift()Elimina primeroarr.shift()
    unshift(x)Añade al inicioarr.unshift(0)
    includes(x)Comprueba existenciaarr.includes(10)
    indexOf(x)Posición del valorarr.indexOf(20)
    join(sep)Convierte a textoarr.join(",")
    slice(a,b)Subarray sin modificararr.slice(1,3)
    splice(a,b)Modifica/elimina/añadearr.splice(1,1)
    reverse()Invierte arrayarr.reverse()
    sort()Ordenaarr.sort()
    concat()Une arraysa.concat(b)
    forEach()Recorre arrayarr.forEach(f)
    map()Transforma elementosarr.map(f)
    filter()Filtra elementosarr.filter(f)
    find()Encuentra elementoarr.find(f)

    Recorrer arrays

    Método clásico

    let numeros = [10,20,30];
    
    for (let i = 0; i < numeros.length; i++) {
      console.log(numeros[i]);
    }

    forEach

    numeros.forEach(function(n) {
      console.log(n);
    });

    map (transformar)

    let dobles = numeros.map(n => n * 2);

    filter (filtrar)

    let mayores = numeros.filter(n => n > 15);

    Arrays con objetos

    let alumnos = [
      {nombre:"Ana", nota:8},
      {nombre:"Luis", nota:5}
    ];
    
    console.log(alumnos[0].nombre);

    Esto es el paso previo al JSON del backend → DOM


    Conceptos clave

    • Los arrays pueden crecer dinámicamente
    • Pueden contener cualquier tipo
    • Son objetos (typeof array → "object")
    • map/filter/find son la base del JavaScript moderno

    Ejercicios para alumnos

    Ejercicio 1

    Crear un array con 5 números y mostrar el tamaño.

    Ejercicio 2

    Añadir un número y eliminar el primero.

    Ejercicio 3

    Mostrar solo los números mayores que 10.

    Ejercicio 4

    Crear un array de nombres y convertirlos a mayúsculas con map.

    Ejercicio 5

    Crear un array de objetos alumno {nombre, nota} y mostrar solo los aprobados.

  • 1.7 – Funciones con JS

    1.7 – Funciones con JS

    Una función es un bloque de código reutilizable que ejecuta una tarea concreta.
    Sirve para organizar, reutilizar y abstraer lógica.

    Idea clave: no repitas código, encapsúlalo.

    Ejemplo mental: una cafetera.
    Entras agua + café → proceso → sale café.
    La función hace exactamente eso, pero con datos.


    2. Sintaxis básica

    function nombreFuncion() {
        // código a ejecutar
    }

    Ejemplo:

    function saludar() {
        console.log("Hola mundo");
    }

    La función no se ejecuta sola. Hay que llamarla:

    saludar();

    3. Funciones con parámetros

    Los parámetros son datos que recibe la función.

    function saludar(nombre) {
        console.log("Hola " + nombre);
    }
    
    saludar("Antonio");
    saludar("Bea");

    La función se adapta al dato. Eso es abstracción.


    4. Retorno de valores (return)

    Una función puede devolver un resultado.

    function saludar(nombre) {
        console.log("Hola " + nombre);
    }
    
    saludar("Antonio");
    saludar("Bea");

    Sin return, la función devuelve undefined.

    Concepto importante:
    return termina la ejecución de la función.


    5. Parámetros vs argumentos

    • Parámetros → variables definidas en la función
    • Argumentos → valores reales que se pasan al llamar
    functionmultiplicar(x, y) {   // parámetrosreturnx*y;}multiplicar(4, 2);             // argumentos

    6. Funciones que llaman a otras funciones

    Las funciones pueden componer comportamiento.

    function cuadrado(n) {
        return n * n;
    }
    
    function mostrarCuadrado(num) {
        let resultado = cuadrado(num);
        console.log(resultado);
    }
    
    mostrarCuadrado(5);

    Esto es modularidad. Construir piezas pequeñas y combinarlas.


    7. Funciones anónimas

    Funciones sin nombre, normalmente guardadas en variables.

    let saludar = function(nombre) {
        return "Hola " + nombre;
    };
    
    console.log(saludar("Carlos"));

    8. Arrow functions (funciones flecha)

    Forma moderna y compacta.

    let sumar = (a, b) => {
        return a + b;
    };

    Si solo hay una línea:

    let sumar = (a, b) => {
        return a + b;
    };

    Si solo hay un parámetro:

    let cuadrado = n => n * n;

    9. Ámbito (scope)

    El scope define dónde existe una variable.

    function prueba() {
        let x = 10;
        console.log(x);
    }
    
    prueba();
    console.log(x); // ERROR

    x solo vive dentro de la función.
    Esto protege el programa de efectos colaterales.


    10. Buenas prácticas

    Nombres claros

    Mal:

    functionf(x) {}

    Bien:

    function calcularTotal(precio, iva) {}

    Funciones pequeñas

    Una función debe hacer una sola cosa.


    Evitar repetir código

    Si copias y pegas → necesitas una función.


    11. Ejemplos prácticos

    Calcular precio con IVA

    function calcularPrecioConIVA(precio) {
        return precio * 1.21;
    }
    
    console.log(calcularPrecioConIVA(100));

    Verificar si un número es par

    function esPar(numero) {
        return numero % 2 === 0;
    }
    
    console.log(esPar(4));
    console.log(esPar(7));

    Convertir JSON recibido del backend (pensando en JEE)

    function pintarUsuario(usuario) {
        console.log("Nombre: " + usuario.nombre);
        console.log("Email: " + usuario.email);
    }
    
    let json = {
        nombre: "Antonio",
        email: "antonio@email.com"
    };
    
    pintarUsuario(json);

    Aquí empieza el puente hacia DOM + datos del servidor.


    12. Ejercicios

    1. Crear función que calcule el área de un rectángulo
    2. Crear función que convierta grados Celsius a Fahrenheit
    3. Crear función que reciba un nombre y devuelva: "Bienvenido <nombre>"
    4. Crear función que reciba un array y devuelva la suma total
  • 2.1 – JSON: Formato de intercambio y almacenamiento de datos

    2.1 – JSON: Formato de intercambio y almacenamiento de datos

    JSON (JavaScript Object Notation) es un formato de texto basado en la estructura de objetos de JavaScript. Más moderno y ligero que XML, se utiliza ampliamente tanto para la transmisión de datos entre aplicaciones como para su almacenamiento.

    Este modelo de datos se ha popularizado porque prioriza el contenido sobre la estructura, reduciendo la cantidad de sintaxis necesaria y facilitando la lectura por parte de humanos y máquinas.


    Estructura básica

    Un archivo JSON es una cadena de texto que debe parsearse (analizarse sintácticamente) para acceder a sus datos. Este proceso se denomina parsing cuando convertimos una cadena en un objeto, y stringification cuando hacemos la operación inversa (objeto → texto).

    Los principales elementos de la estructura JSON son:

    • {}: delimitan un objeto.
    • []: delimitan un array (lista ordenada de elementos).
    • :: separa las claves de sus valores.
    • ,: separa los diferentes pares de clave-valor o elementos.
    • "": delimitan los valores de texto (string).

    Ejemplo de objeto JSON

    {
      "squadName": "Super hero squad",
      "homeTown": "Metro City",
      "formed": 2016,
      "secretBase": "Super tower",
      "active": true,
      "members": [
        {
          "name": "Molecule Man",
          "age": 29,
          "secretIdentity": "Dan Jukes",
          "powers": ["Radiation resistance", "Turning tiny", "Radiation blast"]
        },
        {
          "name": "Madame Uppercut",
          "age": 39,
          "secretIdentity": "Jane Wilson",
          "powers": ["Million tonne punch", "Damage resistance", "Superhuman reflexes"]
        },
        {
          "name": "Eternal Flame",
          "age": 1000000,
          "secretIdentity": "Unknown",
          "powers": ["Immortality", "Heat Immunity", "Inferno", "Teleportation", "Interdimensional travel"]
        }
      ]
    }
    

    Reglas básicas para crear archivos JSON

    1. Los datos se organizan en pares clave:valor, separados por comas.
    2. Tanto claves como valores de texto van entre comillas dobles («»).
    3. Los objetos se delimitan con llaves {}.
    4. Los arrays se delimitan con corchetes [].
    5. Los objetos y arrays pueden anidarse entre sí.

    Ejemplo:

    {
      "nombre": "Jose",
      "edad": 20,
      "genero": "masculino",
      "email": "correodejose@dominio.com",
      "localidad": "Madrid",
      "telefono": "91000000",
      "mando": true,
      "marco": "<iframe width=560 height=315 src='https://www.youtube.com/embed/QCEU-vba8mw' frameborder=0 allowfullscreen></iframe>"
    }
    

    Objetos y arrays en JSON

    • Objeto: se define con llaves {} y contiene uno o varios pares clave-valor.json{ "nombre": "Juan", "apellidos": "Gonzalez" }
    • Array: se define con corchetes [] y puede incluir valores o incluso objetos.json{ "nombre": "Juan", "edad": 30, "coches": ["Ford", "BMW", "Fiat"] }
    • Array de objetos:json{ "nombre": "Juan", "edad": 30, "coches": [ { "nombre": "Ford", "modelos": ["Fiesta", "Focus", "Mustang"] }, { "nombre": "BMW", "modelos": ["320", "X3", "X5"] }, { "nombre": "Fiat", "modelos": ["500", "Panda"] } ] }

    Tipos de datos permitidos

    • string: cadenas de texto.
    • number: números enteros o decimales.
    • object: objetos JSON.
    • array: listas ordenadas.
    • boolean: valores true o false.
    • null: valor nulo o sin asignar.

    JSON vs XML

    JSON y XML son formatos ampliamente usados para intercambiar información entre sistemas y almacenar configuraciones o datos estructurados.

    Aunque JSON suele ser más ligero y fácil de leer, XML ofrece ventajas en casos donde se necesita validación mediante esquemas (XSD) o metadatos complejos.

    Ejemplo JSON:

    {
      "employees": [
        { "firstName": "John", "lastName": "Doe" },
        { "firstName": "Anna", "lastName": "Smith" },
        { "firstName": "Peter", "lastName": "Jones" }
      ]
    }
    

    Ejemplo XML:

    <employees>
      <employee>
        <firstName>John</firstName>
        <lastName>Doe</lastName>
      </employee>
      <employee>
        <firstName>Anna</firstName>
        <lastName>Smith</lastName>
      </employee>
      <employee>
        <firstName>Peter</firstName>
        <lastName>Jones</lastName>
      </employee>
    </employees>
    

    En general, JSON es ideal para intercambio rápido de datos entre aplicaciones web, mientras que XML puede ser preferible en entornos donde se requiera validación formal o compatibilidad con sistemas antiguos.

  • Tor como herramienta de privacidad (no como escondite)

    Tor como herramienta de privacidad (no como escondite)

    Para la realizacion de esta práctica es importante usar:

    Maquina virtual Aislada (NAT)

    VPN

    1. ¿Qué es la deep web?

    Explicación clara y sin mitos:

    • Web superficial: lo indexado por buscadores (Google, Bing).
    • Deep web: contenido no indexado (intranets, foros privados, paneles, correos, Tor).
    • Dark web: pequeña parte de la deep web accesible con Tor.

    Importante: deep web ≠ ilegal.
    La mayoría es aburrida… y eso es buena señal.


    2. ¿Qué es Tor y cómo funciona?

    Tor = The Onion Router

    Conceptos clave:

    • tráfico cifrado en capas (como una cebolla 🧅)
    • múltiples nodos (entrada → intermedio → salida)
    • ningún nodo conoce todo el camino

    Resultado:

    • se oculta el origen del tráfico
    • no se garantiza anonimato absoluto

    Aquí deja clara esta idea:

    Tor reduce rastreo, no elimina la responsabilidad.


    3. Riesgos reales de la deep web (esto es clave)

    Esto es teoría obligatoria, no opcional:

    • ❗ Falsa sensación de anonimato
      • errores humanos = exposición
    • ❗ Malware camuflado
      • PDFs, scripts, descargas “inocentes”
    • ❗ Estafas y desinformación
      • foros que parecen técnicos y no lo son
    • ❗ Contenido ilegal accidental
      • enlaces encadenados sin control
    • ❗ Fingerprinting
      • configuración incorrecta del navegador

    Conclusión clara para el alumno:

    Tor no te protege de malas decisiones.

    Instalación de Tor Browser

    Requisitos

    • Máquina virtual (VirtualBox / VMware)
    • Sistema: Linux (Ubuntu o Debian)
    • NO usar sistema anfitrión

    Instalación de Tor Browser en Ubuntu (método recomendado)

    ⚠️ Importante
    NO vamos a instalar Tor desde apt install torbrowser-launcher
    Para docencia y seguridad, se usa siempre el Tor Browser oficial.


    Requisitos previos

    • Ubuntu Desktop
    • Usuario sin privilegios raros
    • Conexión a Internet
    • VM recomendada (muy recomendable en clase)

    Paso 1 — Descargar Tor Browser (fuente oficial)

    1. Abre el navegador normal (Firefox).
    2. Entra en la web oficial:
    https://www.torproject.org/download/
    
    1. Descarga Tor Browser para Linux (64-bit)
      → se descarga un archivo tipo:
    tor-browser-linux-x86_64-XX.X.tar.xz
    

    Paso 2 — Extraer el archivo

    1. Abre una terminal.
    2. Ve a la carpeta de descargas:
    cd ~/Descargas
    
    1. Extrae el archivo:
    tar -xf tor-browser-linux-x86_64-*.tar.xz
    

    Se creará una carpeta llamada algo como:

    tor-browser
    

    Paso 3 — Ejecutar Tor Browser

    1. Entra en la carpeta:
    cd tor-browser
    
    1. Lanza el navegador:
    ./start-tor-browser.desktop
    

    👉 La primera vez:

    • pulsa Conectar
    • espera a que establezca circuito Tor

    Si ves el mensaje:

    “Congratulations. This browser is configured to use Tor.”

    Todo va bien.


    Paso 4 — Verificar que funciona

    Dentro de Tor Browser:

    1. Abre:
    https://check.torproject.org
    
    1. Debe aparecer:

    ✔ You are using Tor

    1. Observa:
    • IP diferente
    • país distinto al real (normalmente)


    Primeros enlaces civilizados

    • Usa Tor Browser, nada de Chrome con capa ninja.
    • No te registres con correos personales.
    • Lee más de lo que escribes al principio. La deep web premia al observador paciente.

    Foros y comunidades técnicas

    El “Reddit” de Tor, pero con moderación decente en los subforos técnicos.
    Hay secciones de:

    • programación
    • seguridad informática
    • privacidad
    • Linux
      No todo es oro, pero hay debates serios.

    https://dreadytofatroptsdj6io7l3xptbet6onoyno2yv7jicoxknyazubrad.onion


    Los 31 mejores sitios web oscuros y enlaces Onion en Tor (2026)

    Tu guía para los mejores enlaces de la dark web. Encuentra acceso seguro y anónimo a correo electrónico seguro, wikis ocultas, herramientas de Bitcoin y mercados ocultos de internet.

    https://tornews-com.translate.goog/deep-web/lists/dark-web-sites/?_x_tr_sl=auto&_x_tr_tl=es&_x_tr_hl=es


    Tor News

    btenga noticias de ciberseguridad, guías detalladas y conocimientos de expertos sobre Tor, herramientas de privacidad y seguridad digital de profesionales de la industria.

    https://tornews.com


    Tor.link es, dicho sin dramatismos, un directorio y monitor de servicios .onion.
    No es una web “de la deep web” en sí, sino un catálogo que observa la deep web desde fuera.

    Tor.link es un sitio web (accesible desde la web normal y desde Tor) que:

    • cataloga direcciones .onion
    • comprueba si están vivas o muertas
    • muestra metadatos básicos del servicio
    • NO aloja el contenido del .onion

    Es como una ficha técnica o una ITV de servicios Tor.


    ✅ Lo que SÍ hace

    • Te dice si un .onion responde o no
    • Muestra:
      • última vez visto
      • tiempo de respuesta
      • fecha de creación
    • A veces incluye:
      • descripciones
      • firmas PGP
      • capturas antiguas

    ❌ Lo que NO hace

    • No es un buscador “en tiempo real”
    • No garantiza que un enlace sea ético o legal
    • No mantiene vivos los servicios
    • No es Tor ni forma parte del Proyecto Tor

    https://tor.link


    Buscadores

    Ahmia

    http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion/

    http://zb2jtkhnbvhkya3d46twv3g7lkobi4s62tjffqmafjibixk6pmq75did.onion/gdark/search.php

    Listas de Enlaces

    The Hidden Wiki (versión moderada)

    Más directorio que buscador.
    Útil como mapa inicial.

    http://zqktlwiuavvvqqt4ybvgvi7tyo4hjl5xgfuvpdf6otjiycgwqbym2qad.onion

    https://thehiddenwiki.org/

    OnionLinks

    http://s4k4ceiapwwgcm3mkb6e4diqecpo7kvdnfr5gg7sph7jjppqkvwwqtyd.onion/

    ONION.live

    https://onion.live

    dark.fail

    http://darkfailenbsdla5mal2mxn2uz66od5vtzd5qozslagrfzachha3f3id.onion/

    Enlaces .onion civiles y verificados (2026)

    Pégalos tal cual en Tor Browser:

    DuckDuckGo (onion oficial):
    https://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion
    
    Ahmia (buscador de servicios onion, con aviso anti-clones):
    http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvl5ankdibsot4csyd.onion
    
    Dark.Fail (verificador/directorio, útil contra phishing):
    http://darkfailenbsdla5mal2mxn2uz66od5vtzd5qozslagrfzachha3f3id.onion
    

    Y algunos “sitios-serios” (para la práctica, sin morbo):

    Debian (mirror onion):
    http://5ekxbftvqg26oir5wle3p27ax3wksbxcecnm6oemju7bjra2pn26s3qd.onion
    
    Qubes OS (onion):
    http://qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion
    

    Más enlaces, ojo donde te metes

    ONION.live

    Un completo motor de búsqueda de servicios ocultos tipo cebolla en la red oscura.

    https://onion.live


    Sci-Hub (sí, polémico, pero útil)

    Para papers científicos y técnicos que están detrás de muros de pago.
    Especialmente útil si investigas IA, criptografía o redes.

    https://sci-hub.st


    Software libre y proyectos alternativos

    Riseup

    Servicios éticos: correo, listas, documentación técnica, activismo digital.
    Muy usado por desarrolladores y admins paranoicos (en el buen sentido).

    🔗 https://riseup.net
    🔗 Tor: http://vww6ybal4bd7szmgncyruucpgfkqahzddi37ktceo3ah7ngmcopnpyyd.onion/index.es.html



    Filosofía que subyace (esto es importante)

    La deep web útil no va de esconderse, va de control:

    • control de identidad
    • control de datos
    • control de ruido

    Muchos desarrolladores veteranos están ahí porque no quieren algoritmos decidiendo qué leer ni anuncios persiguiéndolos como NPCs rotos.


    Foros y comunidades generales (multi-tema, tono adulto)



    Lectura, ensayo y cultura digital

    The Hidden Wiki (la versión buena)

    Ojo: hay muchas copias horribles.
    Esta es curada y bastante limpia, más directorio que wiki salvaje.

    http://zqktlwiuavvvqqt4ybvgvi7tyo4hjl5xgfuvpdf6otjiycgwqbym2qad.onion/wiki/index.php/Main_Page

    Útil como mapa, no como destino final.


    Biblioteca anónima / textos largos

    Textos sobre:

    • tecnología
    • ética digital
    • privacidad
    • historia de Internet

    No es espectacular, pero es honesta.

    🔗 http://libraryofbabel.info
    (no es Tor-only, pero muy usada desde Tor)


    Tecnología sin ruido comercial

    Linux / Unix discussions (Tor mirrors)

    Foros pequeños, técnicos, sin SEO, sin tutoriales “10 cosas que no sabías”.

    🔗 http://linuxbbq.org
    🔗 mirrors accesibles desde Tor


    DuckDuckGo (versión Tor)

    El más limpio y didáctico para empezar.
    Busca tanto web normal como algunos servicios .onion.

    🔗 https://duckduckgo.com
    🔗 Tor: http://duckduckgogg42xjoc72x3sjasowoarfbgcmvfimaftt6twagswzczad.onion

    ✔ Ideal para:

    • primeras comparativas
    • ver diferencias de resultados
    • no meter ruido

    Ahmia

    Buscador especializado en servicios .onion.
    Filtra bastante contenido ilegal.

    🔗 https://ahmia.fi
    🔗 Tor: http://juhanurmihxlp77nkq76byazcldy2hlmovfu2epvlv6k3cdoviyd.onion

    ✔ Muy recomendable para docencia
    ✔ Transparente sobre lo que indexa y lo que no


    Torch

    Uno de los más antiguos.
    Más “crudo”, pero sigue siendo útil si se usa con criterio.

    🔗 http://torchg2lt7z4k4u7.onion

    ⚠️ Advertencia docente:

    • no usar búsquedas libres
    • solo términos indicados por el profesor

    no todos los enlaces son igual de fiables


    Dark.Fail

    No es buscador de contenido, sino verificador de servicios Tor.
    Sirve para comprobar si un .onion es legítimo o falso.

    🔗 https://dark.fail
    🔗 Tor: http://darkfailenbsd5c.onion

    OnionShare

    OnionShare es una pequeña criatura elegante del ecosistema de la privacidad. Un programa libre que permite compartir archivos, chatear o incluso alojar una web temporal de forma anónima usando la red Tor. Nada de servidores centrales, nada de intermediarios curiosos mirando por la cerradura digital.

    La idea esencial es esta: cuando usas OnionShare, tu propio ordenador se convierte en un mini-servidor oculto dentro de Tor (lo que se llama servicio onion). Genera una dirección .onion única y solo quien tenga ese enlace puede acceder. El archivo no se sube a “la nube”, viaja directamente de tu máquina a la del receptor, cifrado y envuelto en capas como una cebolla criptográfica —de ahí lo de Onion.

    Funciones principales, en lenguaje humano:

    • Compartir archivos anónimamente
      Envías un enlace .onion, el receptor descarga directamente desde tu equipo.
    • Recibir archivos
      Puedes crear un buzón seguro para que otros te envíen cosas sin revelar identidades.
    • Chat privado
      Conversaciones cifradas sin servidores centrales.
    • Modo sitio web
      Hospedar temporalmente una página accesible solo por Tor.

    Detalles curiosos del universo técnico:
    OnionShare usa los onion services de Tor, que evitan exponer tu IP real porque el tráfico nunca sale directamente a Internet “normal”. Todo va dentro de la red Tor. Además, puedes hacer que el enlace sea de un solo uso, que se cierre al descargar, o mantenerlo abierto como un pequeño faro oculto en el océano oscuro.

    Ahora, realidad práctica (la ciencia ama la honestidad):
    No es magia. Si el equipo está comprometido, si compartes datos sensibles sin cuidado, o si el receptor guarda el archivo y lo difunde… la privacidad desaparece. Tor protege el transporte, no las decisiones humanas. La criptografía no arregla imprudencias.

    En el ecosistema de ciberseguridad educativa —que tú sueles cultivar con tus alumnos— OnionShare es perfecto para enseñar:

    • anonimato vs privacidad
    • transferencia directa vs nube
    • modelo de amenaza (threat model)
    • OPSEC básica (seguridad operacional)

    Es una herramienta simple, pero conceptualmente profunda. Una cebolla pequeña que abre puertas enormes hacia el pensamiento crítico sobre identidad, confianza y control en la red.

    🧅 OnionShare


    ✅ Actividad 1 — Comparativa (Normal vs Tor)

    Preparación (obligatoria)

    1. Abre la VM (Ubuntu/Debian).
    2. Asegúrate de tener:
      • un navegador normal (Firefox/Chromium)
      • Tor Browser instalado
    3. Cierra sesiones personales (Google, redes, etc.). No logins.

    1.1 Elegir el sitio (mismo sitio en ambos)

    1. El profesor indica 1 URL permitida (lista cerrada).
    2. Los alumnos copian esa URL en un bloc de notas dentro de la VM (para no equivocarse).

    Regla: no se usa buscador; se pega la URL tal cual.


    1.2 Comparar IP (Normal vs Tor)

    A) Navegador normal

    1. Abre Firefox/Chromium.
    2. Entra en un verificador de IP (elige 1, por ejemplo):
      • https://check.torproject.org/ (sirve también para Tor)
      • https://icanhazip.com/ (muestra IP en texto)
      • https://ifconfig.me/ (similar)
    3. Apunta en el informe:
      • IP que aparece
      • país aproximado (si lo muestra)

    B) Tor Browser

    1. Abre Tor Browser y espera a que conecte.
    2. Entra en el mismo verificador de IP de antes.
    3. Apunta:
      • IP que aparece
      • país aproximado

    ✅ Resultado esperado: las IPs deben ser distintas.


    1.3 Comparar idioma detectado

    1. En navegador normal, visita:
      • https://www.wikipedia.org/
      • o https://www.google.com/ (sin iniciar sesión)
    2. Observa si el sitio:
      • se pone en español automáticamente
      • detecta región/idioma sin preguntar
    3. Repite lo mismo en Tor Browser.

    Anota:

    • ¿sale en español o en otro idioma?
    • ¿te pide elegir idioma/región?

    ✅ Resultado esperado: Tor suele “adivinar” menos tu idioma/región (aunque no siempre).


    1.4 Fingerprint básico (huella del navegador)

    Usaremos una página de prueba legal y educativa.

    A) Navegador normal

    1. Entra en:
      • https://coveryourtracks.eff.org/ (EFF)
    2. Ejecuta la prueba (sin instalar nada).
    3. Anota observaciones simples:
      • ¿te considera “único” o “poco común”?
      • ¿detecta bloqueadores?
      • ¿hay muchos datos recogidos?

    B) Tor Browser

    1. Repite lo mismo en Tor Browser.
    2. Anota diferencias.

    ✅ Resultado esperado: Tor suele parecer “menos único” (más homogéneo) porque muchos usuarios comparten configuración similar.


    ✅ Actividad 2 — Análisis de cabeceras HTTP (Headers)

    Aquí se ve qué “dice” tu navegador cuando pide una página: User-Agent, idioma, etc.

    2.1 Ver headers desde una web (fácil y limpio)

    A) Navegador normal

    1. Abre:
      • https://httpbin.org/headers
    2. Verás un JSON con headers recibidos.
    3. Busca y anota:
      • User-Agent
      • Accept-Language
      • cualquier cosa tipo DNT, Referer (si aparece)

    B) Tor Browser

    1. Abre el mismo enlace en Tor:
      • https://httpbin.org/headers
    2. Anota los mismos campos.

    ✅ Qué comparar

    • User-Agent: ¿es diferente?
    • Accept-Language: ¿manda “es-ES” o algo más neutro?
    • ¿Tor envía menos info o más estandarizada?

    2.2 Bonus opcional (para alumnos más finos)

    Usar otra página equivalente:

    • https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending

    Mismo procedimiento: normal vs Tor, comparar.


    Reglas de seguridad (se imprimen arriba del guion)

    • no interactuar (solo lectura)
    • VM obligatoria
    • sin logins personales
    • no descargar archivos
    • no buscar enlaces nuevos
  • Actividad – Json Invertido

    Actividad – Json Invertido

    Tu tarea es analizar el siguiente código JavaScript y crear el archivo JSON correcto para que funcione sin errores.

    EJERCICIO 1

     Código JavaScript (index.html + script.js)

    Guarda estos archivos y ábrelos en un navegador. (Es  necesario que utilices modo servidor como un contendor o XAMPP)

    https://drive.google.com/file/d/1tK86N1EGZlHKjtxSIHV0TJZ4IcgYyWMd/view?usp=sharingLinks to an external site.

    Si el JSON está bien hecho, al abrir index.html en el navegador debería mostrarse:

    Lista de Productos

    • Tarta de Chocolate – $15 – Stock: 10
    • Cheesecake – $12 – Stock: 5
    • Brownie – $8 – Stock: 7

    EJERCICIO 2

    Tu tarea es analizar el código JavaScript y crear el archivo JSON correcto para que funcione sin errores.

    Código JavaScript (index.html + script.js)

    Guarda estos archivos y ábrelos en un navegador.

    https://drive.google.com/file/d/1spFSlotW1K6Cnm-N5LejSGQhn79phaAd/view?usp=sharingLinks to an external site.

  • Instalación y Primeros Pasos con Docker en Windows

    Instalación y Primeros Pasos con Docker en Windows

    Hay conceptos que, una vez se ven, el cerebro hace clic y ya no vuelve atrás. La diferencia entre máquinas virtuales y contenedores es uno de esos momentos fundacionales en la vida de cualquier persona que empieza a pensar como ingeniero de sistemas.

    La metáfora clásica —y sorprendentemente precisa— es esta:

    👉 Las máquinas virtuales son casas completas.
    👉 Los contenedores son apartamentos dentro del mismo edificio.

    La diferencia que cambia la forma de diseñar sistemas

    Esto es lo verdaderamente importante —y lo que merece que tus alumnos lo entiendan bien:

    Con VMs piensas en:

    «Voy a crear servidores.»

    Con contenedores empiezas a pensar:

    «Voy a desplegar servicios.»

    Instalación de Docker Desktop y Portainer en Windows

    En los entornos tecnológicos actuales, la virtualización ligera mediante contenedores se ha convertido en un estándar para el desarrollo, despliegue y administración de aplicaciones.

    Docker es una plataforma que permite empaquetar aplicaciones junto con todas sus dependencias dentro de contenedores, garantizando que funcionen de forma idéntica en cualquier sistema.

    En este tema aprenderemos a preparar un equipo Windows para trabajar con Docker Desktop y a instalar Portainer, una herramienta gráfica que facilita la gestión de contenedores.

    Esta instalación será la base de todos los proyectos que realizaremos posteriormente.


    1. ¿Por qué Docker necesita Linux en Windows?

    Docker utiliza tecnologías propias del kernel de Linux como:

    • namespaces → aislamiento de procesos
    • cgroups → control de recursos
    • union filesystems → capas de almacenamiento

    Windows no dispone de estas tecnologías de forma nativa.

    La solución es WSL2.


    ¿Qué es WSL?

    WSL (Windows Subsystem for Linux) es una característica de Windows que permite ejecutar un kernel real de Linux dentro del sistema operativo sin necesidad de usar una máquina virtual tradicional.

    • No es un emulador.
    • No es una traducción de comandos.
    • Es Linux funcionando dentro de Windows.

    Ventajas de WSL2 frente a una VM clásica:

    • Arranque casi instantáneo
    • Menor consumo de memoria
    • Mejor rendimiento de disco
    • Integración directa con el sistema

    Docker Desktop utiliza WSL2 como motor de virtualización.

    👉 Sin WSL2, Docker simplemente no puede funcionar correctamente en Windows moderno.



    3. Activar la virtualización

    La virtualización debe estar habilitada en la BIOS/UEFI. Si has estado trabajando con maquinas virtuales con Virtual Box o VMWare seguro que ya lo tienes.

    Cómo comprobarlo
    1. Abrir el Administrador de tareas
    2. Ir a la pestaña Rendimiento → CPU

    Debe aparecer:

    Virtualización: Habilitada
    

    Si está deshabilitada:

    • Reiniciar el equipo
    • Entrar en BIOS/UEFI
    • Activar alguna de estas opciones:
    Intel VT-x
    Intel Virtualization Technology
    AMD-V
    SVM Mode
    

    Guardar cambios y reiniciar.


    4. Instalación de WSL2

    Abrir PowerShell como administrador.

    Ejecutar:

    wsl --install
    

    Este comando realiza automáticamente:

    • Instalación del kernel Linux
    • Activación de componentes necesarios
    • Instalación de Ubuntu
    • Configuración de WSL2 como versión por defecto

    Reiniciar el equipo cuando lo solicite.


    Comprobar que WSL2 está funcionando

    wsl -l -v
    

    Resultado esperado:

    NAME      STATE    VERSION
    Ubuntu    Running  2
    

    Si aparece versión 1:

    wsl --set-version Ubuntu 2
    

    5. Instalación de Docker Desktop

    Descargar desde la web oficial: https://www.docker.com/products/docker-desktop/

    Evitar instaladores de terceros.


    Instalación

    Ejecutar el instalador.

    Durante el proceso es MUY importante verificar que esté marcada la opción:

    ✅ Use WSL 2 instead of Hyper-V

    Esto permitirá que Docker funcione con el backend moderno.

    Finalizar la instalación y reiniciar si es necesario.


    6. Primer arranque de Docker

    Abrir Docker Desktop desde el menú inicio.

    El primer arranque puede tardar unos minutos.

    Cuando Docker esté listo aparecerá el mensaje:

    Docker is running
    

    Verificación desde terminal

    Abrir PowerShell o CMD:

    docker version
    

    Si todo está correcto, se mostrará información del cliente y del servidor Docker.

    Probar el primer contenedor:

    docker run hello-world
    

    Si aparece un mensaje de bienvenida, la instalación es correcta.

    Este pequeño contenedor confirma que:

    • Docker descarga imágenes
    • Puede crear contenedores
    • El motor funciona

    7. Configuración recomendada de Docker Desktop

    Ir a:

    Settings → Resources
    

    Asignación recomendada:

    • RAM: 4–6 GB
    • CPU: 2 o más
    • Swap: 1–2 GB

    Si los equipos son potentes, aumentar estos valores mejora la experiencia.


    8. ¿Qué es Portainer?

    Portainer es una interfaz web que permite administrar Docker sin depender únicamente de la terminal.

    Con Portainer es posible:

    • Crear contenedores
    • Gestionar imágenes
    • Administrar volúmenes
    • Supervisar recursos
    • Eliminar servicios

    Es una herramienta muy utilizada en entornos profesionales y facilita enormemente el aprendizaje inicial.


    9. Instalación de Portainer

    Docker desktop permite instalar Portainter como un plugin mas.

    Si deseas hacerlo desde terminal tambien puedes:

    Crear un volumen para almacenar los datos de Portainer.

    docker volume create portainer_data
    

    Ahora ejecutamos el contenedor:

    docker run -d -p 9443:9443 \
    --name portainer \
    --restart=always \
    -v /var/run/docker.sock:/var/run/docker.sock \
    -v portainer_data:/data \
    portainer/portainer-ce
    

    ¿Qué estamos haciendo?

    • -d → ejecuta el contenedor en segundo plano
    • -p 9443:9443 → expone la interfaz web
    • docker.sock → permite a Portainer comunicarse con Docker
    • volumen /data → guarda la configuración

    10. Primer acceso a Portainer

    Abrir el navegador:

    https://localhost:9443
    

    Es normal que el navegador advierta sobre el certificado.

    Continuar igualmente.




    Problemas habituales

    Docker no arranca

    Generalmente ocurre porque:

    • WSL no está activo
    • Virtualización deshabilitada
    • Conflictos con Hyper-V

    Solución típica:

    wsl --update
    wsl --shutdown
    

    Reiniciar Docker.


    Error de memoria

    Asignar más RAM desde:

    Settings → Resources
    

    WSL extremadamente lento

    Ejecutar:

    wsl --shutdown
    

    Y reiniciar Docker.


    A partir de aquí comenzaremos a trabajar con:

    • imágenes
    • contenedores
    • redes
    • volúmenes
    • orquestación

  • Docker desde Terminal

    Docker desde Terminal

    Antes de comenzar la misión, tu equipo debe estar preparado.

    Docker será el motor que dará vida a toda la infraestructura.

    Instalar Docker correctamente desde la terminal en Ubuntu utilizando el repositorio oficial.

    Evita instalar versiones antiguas desde repositorios genéricos.

    Queremos herramientas profesionales.


    Actualizar el sistema

    sudo apt update
    sudo apt upgrade -y
    

    Esto reduce la probabilidad de conflictos de dependencias.

    Los ingenieros prudentes actualizan primero.


    Instalar paquetes necesarios

    sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
    

    Estos paquetes permiten a Ubuntu comunicarse de forma segura con repositorios externos.


    Añadir la clave oficial de Docker

    curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
    

    Una clave GPG verifica que el software proviene de la fuente legítima.

    Sin esto, cualquiera podría hacerse pasar por Docker.

    Y eso sería… una idea terrible.


    Añadir el repositorio oficial

    echo \
      "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker.gpg] \
      https://download.docker.com/linux/ubuntu \
      $(lsb_release -cs) stable" | \
      sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
    

    Ahora Ubuntu sabrá dónde buscar Docker.


    Instalar Docker Engine

    sudo apt update
    sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
    

    Aquí ocurre la magia.


    Verificar la instalación

    sudo systemctl status docker
    

    Debe aparecer como:

    👉 active (running)

    Ahora prueba:

    sudo docker run hello-world
    

    Si ves el mensaje de bienvenida…

    Docker está vivo.


    MUY recomendado — Usar Docker sin sudo

    Trabajar con sudo constantemente es incómodo.

    Haz esto:

    sudo usermod -aG docker $USER
    

    Después CIERRA SESIÓN o reinicia.

    No es opcional — el cambio de grupo necesita recargar permisos.

    Comprueba:

    docker run hello-world
    

    Video de la lección

    Crear y ejecutar contenedores

    Contenedor interactivo básico

    docker run -it ubuntu
    

    Qué ocurre aquí:

    • run → crea el contenedor si no existe
    • -i → mantiene STDIN abierto
    • -t → asigna terminal
    • ubuntu → imagen base

    Si no está descargada, Docker la bajará automáticamente.

    Para salir sin detener el contenedor:

    Ctrl + P + Q
    

    Para salir deteniéndolo:

    exit
    

    Nombrar un contenedor

    docker run -it --name mi-ubuntu ubuntu
    

    Nombrar contenedores evita trabajar con IDs largos e ilegibles.

    Tu yo del futuro te lo agradecerá.


    Persistencia usando carpeta del host

    docker run --name mi-ubuntu -it -v /datos-persistentes:/datos ubuntu
    

    Qué significa esto:

    HOST → CONTENEDOR
    /datos-persistentes → /datos
    

    Todo lo que guardes en /datos sobrevivirá aunque borres el contenedor.

    Si la carpeta no existe, Docker la crea.


    Persistencia usando volumen Docker (RECOMENDADO)

    Primero crea el volumen:

    docker volume create mi-volumen
    

    Ahora úsalo:

    docker run --name mi-ubuntu -it -v mi-volumen:/datos ubuntu
    

    👉 Docker gestionará la ubicación real del almacenamiento.

    Ventajas:

    • Más seguro
    • Mejor rendimiento
    • Independiente del sistema de carpetas

    ⚠️ Nota para Windows

    docker run -it -v C:\ruta\local:/ruta/en/contenedor ubuntu
    

    En Ubuntu Desktop NO se usa esta sintaxis.

    La equivalente sería:

    docker run -it -v /home/usuario/datos:/datos ubuntu
    

    Consultar información del sistema Docker

    Ver contenedores en ejecución

    docker ps
    

    Ver TODOS los contenedores

    docker ps -a
    

    Aquí aparecerán también los detenidos.

    Muy útil para debugging.


    Ver imágenes descargadas

    docker images
    

    O su versión moderna:

    docker image ls
    

    Crear imágenes personalizadas

    Imagina que has instalado paquetes dentro del contenedor y no quieres repetir el proceso.

    Puedes congelar ese estado.

    docker commit mi-ubuntu mi-imagen-personalizada
    

    Ahora tienes una nueva imagen lista para usar:

    docker run -it mi-imagen-personalizada
    

    📌 Importante para mentalidad profesional:

    docker commit es útil para aprender…

    Pero en entornos reales se prefiere usar Dockerfile porque permite reproducibilidad.


    Operaciones con contenedores

    Arrancar un contenedor detenido

    docker start mi-ubuntu
    

    Arrancar y conectarte directamente

    docker start -ai mi-ubuntu
    

    Parámetros:

    • -a → attach (conectar terminal)
    • -i → modo interactivo

    Ejecutar comandos dentro de un contenedor activo

    docker exec -it mi-ubuntu bash
    

    Esto abre una nueva shell.

    Extremadamente usado por administradores.


    Eliminar un contenedor

    ⚠️ Debe estar detenido.

    docker rm mi-ubuntu
    

    Para forzar:

    docker rm -f mi-ubuntu
    

    Limpiar contenedores detenidos automáticamente

    docker container prune
    

    Docker pedirá confirmación.

    Este comando es famoso por liberar gigas de disco en laboratorios.

  • Del Contenedor a la Base de Datos: MySQL Docker + Workbench

    Del Contenedor a la Base de Datos: MySQL Docker + Workbench

    Vamos a creae una base de datos naciendo en un contenedor, y desde fuera un cliente elegante (Workbench) hablando con ella a través del vacío digital. Eso es red, puertos y aislamiento en acción.

    1. Crear contenedor MySQL.
    2. Publicar puerto al host.
    3. Conectarse desde MySQL Workbench.
    4. Ver que el contenedor es “otro sistema”, pero accesible.

    Arquitectura:

    Workbench (Host)  →  localhost:3306  →  Contenedor MySQL

    Paso 1 — Crear contenedor MySQL

    En terminal:

    docker run -d \
      --name mysql-demo \
      -e MYSQL_ROOT_PASSWORD=1234 \
      -e MYSQL_DATABASE=demo \
      -p 3306:3306 \
      mysql:8

    Qué significa cada parte (esto es lo que debes explicar)

    • -d → modo daemon (segundo plano)
    • --name mysql-demo → nombre del contenedor
    • MYSQL_ROOT_PASSWORD → password del root (obligatorio)
    • MYSQL_DATABASE → crea BD inicial
    • -p 3306:3306 → publica puerto MySQL al host
    • mysql:8 → imagen oficial

    Paso 2 — Verificar que el contenedor está vivo

    docker ps

    Debe aparecer algo como:

    mysql-demo   mysql:8   Up ...   0.0.0.0:3306->3306/tcp

    Si no arranca:

    docker logs mysql-demo

    MySQL tarda unos segundos en inicializar. Paciencia científica.


    Paso 3 — Conectar desde MySQL Workbench

    En Workbench → New Connection

    Parámetros:

    • Host: 127.0.0.1
    • Port: 3306
    • User: root
    • Password: 1234

    Test Connection → Connect.

    Si todo va bien, verás la BD demo.


    Paso 4 — Prueba real

    En Workbench ejecuta:

    CREATE TABLE alumnos (
      id INT AUTO_INCREMENT PRIMARY KEY,
      nombre VARCHAR(50)
    );
    
    INSERT INTO alumnos (nombre) VALUES ('Neo'), ('Trinity');
    
    SELECT * FROM alumnos;

    Luego demuestra algo mágico:

    Entra al contenedor

    docker exec -it mysql-demo mysql -uroot-p1234

    Dentro:

    USE demo;
    SELECT * FROM alumnos;

    Los datos están ahí → Workbench y contenedor hablan con la misma base.

    Eso hace que los alumnos comprendan el concepto de servicio expuesto por red.

    Problemas típicos (para que no te sabotee el universo)

    Puerto ocupado

    Si tienes MySQL local:

    lsof -i :3306

    Cambia puerto:

    -p3307:3306

    Y en Workbench → puerto 3307.


    No conecta

    Comprobar:

    docker ps
    docker logs mysql-demo

    Esperar inicialización (MySQL tarda).


    Workbench no conecta pero CLI sí

    A veces el plugin de auth:

    docker exec -it mysql-demo mysql -uroot-p1234

    En SQL

    ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '1234';
    FLUSH PRIVILEGES;
  • Del Código al Contenedor: Dominando Dockerfile Paso a Paso

    Del Código al Contenedor: Dominando Dockerfile Paso a Paso

    Un Dockerfile es una receta: describes pasos para construir una imagen.
    Luego ejecutas esa imagen y eso crea un contenedor.

    • Dockerfile: receta
    • Imagen: “plato ya cocinado” (plantilla)
    • Contenedor: “plato servido” (instancia en ejecución)

    Primer Dockerfile “Hola Mundo” (Python)

    Estructura de proyecto:

    mkdir dockerfile-101 && cd dockerfile-101
    mkdir app

    Crea app/app.py:

    cat > app/app.py << 'EOF'
    print("Hola desde un contenedor 😼")
    EOF

    Crea Dockerfile:

    FROM python:3.12-slim
    
    WORKDIR /app
    COPY app/ /app/
    
    CMD ["python", "app.py"]
    EOF

    Construir la imagen:

    docker build -t hola-dockerfile:1.0 .

    Ejecutar:

    docker run --rm hola-dockerfile:1.0

    Puntos clave :

    • Qué hace FROM, WORKDIR, COPY, CMD.
    • Por qué CMD va en formato lista (["..."]) y no como string.

    FROM

    Define la imagen base sobre la que se construirá la nueva imagen.

    Ejemplo:

    FROM python:3.12-slim

    Qué ocurre:

    • Docker descarga la imagen si no existe localmente.
    • Marca el punto de partida del sistema de archivos del contenedor.
    • Solo puede existir una FROM por etapa (en multi-stage puede haber varias).

    Buenas prácticas:

    • Usar imágenes ligeras (alpine, slim).
    • Evitar latest en producción (usar versiones concretas).

    WORKDIR

    Establece el directorio de trabajo dentro del contenedor.
    Equivale a ejecutar cd permanentemente para las siguientes instrucciones.

    WORKDIR /app

    Qué ocurre:

    • Si el directorio no existe, Docker lo crea automáticamente.
    • Todas las instrucciones posteriores (COPY, RUN, CMD) se ejecutan desde esa ruta.

    Ventaja:
    Evita rutas largas y mejora la legibilidad.


    COPY

    Copia archivos desde el sistema host (tu máquina) al contenedor.

    COPY app/ /app/

    Qué ocurre:

    • Se copian los archivos del contexto de build (directorio actual).
    • Se crea una nueva capa en la imagen.
    • Si cambia cualquier archivo copiado, Docker invalida la caché desde ese punto.

    Diferencia con ADD:

    • COPY solo copia archivos.
    • ADD puede descomprimir tar y descargar URLs (menos predecible, se recomienda COPY).

    Buenas prácticas:
    Copiar primero dependencias y luego código para aprovechar la caché:

    COPY requirements.txt .RUN pip install -r requirements.txtCOPY . .

    CMD

    Define el comando por defecto que ejecutará el contenedor al iniciarse.

    CMD ["python", "app.py"]

    Si el usuario pasa otro comando en docker run, este sobrescribe CMD.

    Ejemplo:

    docker run mi-imagen python otro.py

    ¿Por qué CMD debe ir en formato lista?

    Existen dos formas:

    Forma shell (string)

    CMD python app.py

    Docker lo ejecuta así:

    /bin/sh -c "python app.py"

    Problemas:

    • Se crea un proceso intermedio (sh).
    • Señales Unix (SIGTERM, SIGINT) no llegan correctamente al proceso principal.
    • Problemas con contenedores que deben parar limpiamente (servidores, apps, etc.).

    Forma exec (lista) — RECOMENDADA

    CMD ["python", "app.py"]

    Ventajas:

    • No usa shell intermedia.
    • El proceso es PID 1 dentro del contenedor.
    • Recibe correctamente señales del sistema.
    • Comportamiento más predecible.
    • Es el estándar en producción.

    Regla mental:
    Si el comando no necesita shell (|, &&, variables, etc.) → usar formato lista.

    EXPOSE

    Documenta qué puerto usa la aplicación dentro del contenedor.

    EXPOSE80

    Importante:

    • No abre puertos.
    • Solo sirve como metadato informativo.
    • Para publicar puerto se usa -p en docker run.

    Ejemplo:

    docker run -p8080:80 mi-imagen

    ENV

    Define variables de entorno dentro del contenedor.

    ENV APP_ENV=production

    Uso típico:

    • Configuración de aplicaciones
    • Rutas
    • Flags de ejecución

    Acceso en Python:

    importosprint(os.getenv("APP_ENV"))

    RUN

    Ejecuta comandos durante la construcción de la imagen.

    RUN apt update && apt install -y curl

    Diferencia con CMD:

    • RUN ocurre en build
    • CMD ocurre en runtime

    Cada RUN crea una capa nueva → conviene agrupar comandos.


    Dockerfile con dependencias (requests) + capas

    Cambia app/app.py:

    
    
    
    
    
    import requests
    print("IP pública (si hay salida a Internet):", requests.get("https://api.ipify.org").text)
    

    Crea app/requirements.txt:

    cat > app/requirements.txt << 'EOF'
    requests==2.32.3
    EOF

    Actualiza Dockerfile (truco de cache y capas):

    FROM python:3.12-slim
    
    WORKDIR /app
    
    # 1) Copiamos requirements primero (mejor cache)
    COPY app/requirements.txt /app/requirements.txt
    RUN pip install --no-cache-dir -r requirements.txt
    
    # 2) Copiamos el código después
    COPY app/ /app/
    
    CMD ["python", "app.py"]
    

    Rebuild y run:

    docker build -t ip-check:1.0 .
    docker run --rm ip-check:1.0

    Lección nerd útil: si solo cambia el código, Docker reutiliza la capa de pip install y construye más rápido.


    .dockerignore (para no meter “basura” en la imagen)

    Crea .dockerignore:

    .git
    __pycache__/
    *.pyc
    *.log
    .DS_Store
    

    Crear un archivo “gordo” y comprobar que no entra:

    dd if=/dev/zero of=archivo_gordo.bin bs=1M count=50
    docker build -t ignore-test:1.0 .


    Dockerfile para una web (Nginx estático) en 30 segundos

    Estructura:

    mkdir -p web
    cat > web/index.html << 'EOF'
    <h1>Hola desde Nginx en Docker</h1>
    <p>Si ves esto, EXPOSE era postureo, pero ayuda a documentar 😄</p>
    EOF

    Dockerfile:

    cat > Dockerfile << 'EOF'
    FROM nginx:alpine
    COPY web/ /usr/share/nginx/html/
    EXPOSE 80
    EOF

    Build + run:

    docker build -t web-nginx:1.0 .
    docker run --rm -p 8080:80 web-nginx:1.0

    Abrir: http://localhost:8080


    Ejemplos

    Ejemplo: Dockerfile para una app en Python

    FROM python:3.11-slim
    WORKDIR /app
    COPY requirements.txt .
    RUN pip install -r requirements.txt
    COPY . .
    EXPOSE 5000
    
    CMD ["python", "app.py"]

    Este caso muestra cómo:

    • Se usa una imagen base de Python.
    • Se instala lo necesario con pip.
    • Se copia el código de la aplicación.
    • Se expone el puerto del servicio (por ejemplo, Flask).
    • Se ejecuta la app con CMD.

    Ejemplo: Dockerfile para PHP + Apache

    FROM php:8.2-apache
    COPY ./htdocs /var/www/html/
    EXPOSE 80

    Así pueden tener un servidor web con PHP.
    Luego ejecutan:

    docker build -t miwebphp . docker run -d -p 8080:80 miwebphp

    Buenas prácticas

    • Siempre usa imágenes base oficiales.
    • Agrupa las instalaciones en una sola instrucción RUN para reducir el tamaño de la imagen.
    • Usa .dockerignore para no copiar archivos innecesarios.
    • Define variables con ENV si hay configuraciones reutilizables.
    • Usa ENTRYPOINT cuando quieras ejecutar siempre el mismo comando, incluso si el usuario añade argumentos extra.

    Instrucción WORKDIR

    WORKDIR establece el directorio de trabajo dentro del contenedor.
    Equivale a hacer un cd /app dentro del entorno del contenedor antes de ejecutar los siguientes comandos.

    Por ejemplo:

    FROM python:3.11-slim
    WORKDIR /app
    COPY . .
    RUN pip install -r requirements.txt
    
    CMD ["python", "app.py"]

    Qué hace realmente:

    1. Crea el directorio si no existe (/app en este caso).
    2. Cambia el contexto: a partir de esa línea, todos los comandos (COPY, RUN, CMD, etc.) se ejecutan dentro de /app.

    Así, COPY . . copia el contenido del proyecto local dentro del contenedor en /app, y python app.py se ejecutará desde ahí.


    Sin WORKDIR

    Si no la usas, Docker ejecuta todo desde / (la raíz del contenedor).
    Ejemplo:

    FROM python:3.11-slim
    
    COPY . .
    
    CMD ["python", "app.py"]

    Esto también funcionará, pero el código quedará desperdigado en / — algo poco limpio y poco profesional.


    ¿Qué son las variables de entorno en Docker?

    Las variables de entorno (ENV) son valores que se inyectan en el entorno del contenedor y que las aplicaciones pueden usar para configurarse.

    Por ejemplo:

    • Contraseña del root
    • Nombre de la base de datos
    • Usuario y contraseña de aplicación

    Docker las pasa al contenedor con la instrucción ENV en el Dockerfile o con la opción -e en el docker run.


    Ejemplo básico de Dockerfile con MySQL

    # Imagen base oficial de MySQL
    
    FROM mysql:8.0
    
    # Variables de entorno
    
    ENV MYSQL_ROOT_PASSWORD=supersegura
    
    ENV MYSQL_DATABASE=tienda
    
    ENV MYSQL_USER=usuario
    
    ENV MYSQL_PASSWORD=1234
    
    # Exponer el puerto de MySQL
    
    EXPOSE 3306

    Explicación:

    • MYSQL_ROOT_PASSWORD: establece la contraseña del usuario root.
    • MYSQL_DATABASE: crea automáticamente una base de datos llamada tienda.
    • MYSQL_USER y MYSQL_PASSWORD: crean un usuario adicional con permisos sobre esa base.
    • EXPOSE 3306: indica el puerto por defecto del servicio.

    Construcción y ejecución

    Construir la imagen:

    docker build -t mysql-demo .

    Ejecutar el contenedor:

    docker run -d -p 3306:3306 --name contmysql mysql-demo

    Con eso, MySQL arrancará con la configuración establecida en las variables del Dockerfile.


    Alternativa más flexible (sin tocar el Dockerfile)

    También se pueden pasar las variables en tiempo de ejecución, lo que se recomienda para producción (para no dejar contraseñas dentro del Dockerfile):

    docker run -d -p 3306:3306 \
    
    --name mysql-demo \
    
    -e MYSQL_ROOT_PASSWORD=supersegura \
    
    -e MYSQL_DATABASE=tienda \
    
    -e MYSQL_USER=usuario \
    
    -e MYSQL_PASSWORD=1234 \
    
    mysql:8.0

    Así puedes usar directamente la imagen oficial de MySQL sin construir una nueva.


    Comprobación dentro del contenedor

    Para entrar al contenedor y verificar:

    docker exec -it mysql-demo mysql -u root -p

    Introduce la contraseña (supersegura) y luego:

    SHOW DATABASES;

    Verás que existe la base tienda.


    Usando un .env externo

    Otra práctica útil es usar un archivo .env:

    Archivo .env

    MYSQL_ROOT_PASSWORD=supersegura
    
    MYSQL_DATABASE=tienda
    
    MYSQL_USER=usuario
    
    MYSQL_PASSWORD=1234

    Y luego ejecutarlo con:

    docker run -d --env-file .env -p 3306:3306 --name mysql-demo mysql:8.0

    LABORATORIO – TAREA

    Montar una infraestructura de laboratorio Dockerizada donde cada contenedor representa una parte de una red vulnerable, simulando un pequeño entorno que deben administrar, securizar o incluso “atacar” de forma controlada.


    Cada alumno desplegará una red interna en su máquina virtual Ubuntu Server, con varios contenedores Docker que simulen los componentes de una empresa ficticia hackeable llamada:

    «CyberCorp Ltd.»

    El propósito es:

    • Divertirse con un entorno “ethical hacking friendly”.
    • Aprender a crear y gestionar contenedores.
    • Comprender la comunicación entre ellos
    • Aplicar conceptos de seguridad: contraseñas, puertos, logs, aislamiento, backups.

    Infraestructura propuesta

    ServicioImagen baseRol / DescripciónPuertos
    nginx-webnginx:latestPágina corporativa vulnerable (HTML + PHP)8080
    db-servermysql:8.0Base de datos de empleados con credenciales débiles3306
    ftp-serverdelfer/alpine-ftp-serverServidor FTP para intercambio de archivos21
    mail-servermaildev/maildevServidor SMTP simulado (visualización de correos en web)1080
    monitorgrafana/grafanaPanel de monitorización interno3000
    attackerkalilinux/kali-rollingContenedor con herramientas ofensivasshell interactiva
    loggerfluentdCentralización de l

    1) Preparación en la VM (comandos iniciales)

    # Actualizar y asegurarnos de tener Docker
    sudo apt update && sudo apt install -y docker.io
    # Iniciar y activar Docker
    sudo systemctl enable --now docker
    # Añadir tu usuario al grupo docker (opcional, cerrar sesión/reiniciar)
    sudo usermod -aG docker $USER
    # Crear red y volumenes
    docker network create cybernet
    docker volume create mysql_data
    docker volume create web_html
    

    2) Estructura de carpetas (ejemplo) /home/usuario/hack-containers/

    ├─ web/
    │  ├─ Dockerfile
    │  └─ html/
    │     ├─ index.php
    │     └─ secret/flag.txt
    ├─ mysql/
    │  ├─ Dockerfile
    │  └─ init-db/
    │     └─ init.sql
    ├─ ftp/
    │  └─ Dockerfile
    ├─ mail/
    │  └─ Dockerfile
    ├─ attacker/
    │  └─ Dockerfile
    └─ logger/
       └─ Dockerfile

    3) Dockerfile + archivos — ejemplos

    A) MySQL (mysql/Dockerfile)

    Usamos la imagen oficial de MySQL como base, y añadimos un init SQL.

    FROM mysql:8.0
    
    # Copiamos scripts de inicialización (se ejecutan al primer arranque)
    
    COPY init-db/ /docker-entrypoint-initdb.d/ VOLUME ["/var/lib/mysql"]
    
    EXPOSE 3306

    mysql/init-db/init.sql (ejemplo con credenciales débiles y tabla)

    CREATE DATABASE empleados;
    
    USE empleados;
    
    CREATE TABLE usuarios ( id INT AUTO_INCREMENT PRIMARY KEY, usuario VARCHAR(50), password VARCHAR(50) );
    
    INSERT INTO usuarios (usuario, password) VALUES ('admin','admin123');

    Construir y ejecutar:

    cd mysql
    
    docker build -t ctf-mysql:1.0 . docker run -d --name mysql --network cybernet \
    
    -e MYSQL_ROOT_PASSWORD=rootroot \
    
    -v mysql_data:/var/lib/mysql \
    
    ctf-mysql:1.0

    B) Web vulnerable (PHP + Apache) (web/Dockerfile)

    FROM php:8.2-apache
    
    # Copiamos el código vulnerable
    
    COPY html/ /var/www/html/
    
    # Habilitamos mod_rewrite por si hace falta
    
    RUN a2enmod rewrite
    
    EXPOSE 80

    web/html/index.php (vulnerable ejemplo: login sin sanitizar — para SQLi)

    <?php
    $conn = new mysqli('mysql','root','rootroot','empleados');
    if(isset($_GET['user'])){
        $user = $_GET['user'];
        $res = $conn->query("SELECT * FROM usuarios WHERE usuario = '$user'");
        if($res && $res->num_rows){
            echo "Usuario encontrado<br>";
        } else {
            echo "No encontrado";
        }
    } else {
        echo '<a href="?user=admin">Comprobar usuario admin</a>';
    }
    ?>

    web/html/secret/flag.txt

    FLAG{has_encontrado_la_bandera_web}

    Construir y ejecutar:

    cd web
    docker build -t ctf-web:1.0 .
    docker run -d --name web --network cybernet \
      -p 8080:80 \
      -v web_html:/var/www/html \
      ctf-web:1.0
    # Copiar el html local al volumen (una sola vez si quieres)
    docker cp html/. web:/var/www/html/

    Nota: en index.php se conecta a host mysql (nombre del contenedor) — así los containers se resuelven por nombre dentro de la red cybernet.


    C) FTP (ftp/Dockerfile) — ejemplo simple con vsftpd

    FROM alpine:3.18
    RUN apk add --no-cache vsftpd openrc
    COPY ftp-config/vsftpd.conf /etc/vsftpd/vsftpd.conf
    # Creamos usuario demo
    RUN adduser -D -h /home/usuario ftpuser && \
        echo "ftpuser:ftp123" | chpasswd && \
        mkdir -p /home/usuario/ftp_upload && chown ftpuser:ftpuser /home/usuario/ftp_upload
    EXPOSE 21 20
    CMD ["sh", "-c", "vsftpd /etc/vsftpd/vsftpd.conf"]

    ftp-config/vsftpd.conf puede ser muy simple para prácticas. (Puedes proveerlo a los alumnos o generar uno básico.)

    Construir y ejecutar:

    cd ftp
    
    docker build -t ctf-ftp:1.0 .
    
    docker run -d --name ftp --network cybernet -p 2121:21 ctf-ftp:1.0

    (Nota: FTP activo/pasivo considera puertos extra; para la práctica usarlo localmente y documentar.)


    D) Maildev (mail server de pruebas) — Dockerfile mínimo

    FROM maildev/maildev:latest 
    EXPOSE 1080 25

    Construir y ejecutar:

    cd mail
    
    docker build -t ctf-mail:1.0 .
    
    docker run -d --name mail --network cybernet -p 1080:1080 ctf-mail:1.0

    Maildev ofrece UI web en :1080 para ver emails enviados por la aplicación vulnerable.


    E) Logger / ELK ligero (logger/Dockerfile) — ejemplo usando busybox+fluentd sería largo.

    Puedes usar Fluentd o simplemente montar un contenedor que recoja docker logs desde fuera. Para simplicidad, propondré un contenedor fluentd base:

    FROM fluent/fluentd:v1.14-1
    
    EXPOSE 24224

    Construir y ejecutar:

    cd logger
    
    docker build -t ctf-logger:1.0 .
    
    docker run -d --name logger --network cybernet -p 24224:24224 ctf-logger:1.0

    F) Contenedor atacante (Kali) (attacker/Dockerfile)

    Instalamos unas herramientas útiles (nmap, nikto, sqlmap, hydra).

    FROM kalilinux/kali-rolling
    RUN apt update && apt install -y nmap nikto sqlmap hydra netcat-openbsd curl && apt clean
    WORKDIR /root
    CMD ["/bin/bash"]

    Construir y ejecutar (modo interactivo):

    cd attacker
    
    docker build -t ctf-kali:1.0 .
    
    docker run -it --name kali --network cybernet ctf-kali:1.0

    Dentro del contenedor atacas la red cybernet (ej. nmap -sV -p- web).


    4) Notas sobre volúmenes y persistencia

    Para copiar archivos iniciales al volumen, puedes docker cp como mostré.

    Mysql usa -v mysql_data:/var/lib/mysql para persistencia.

    Web usamos -v web_html:/var/www/html para poder editar fuera y reflejar cambios.

    RECUERDA

    # Ver containers
    docker ps -a

    # Logs de un contenedor
    docker logs web

    # Entrar a un contenedor
    docker exec -it mysql bash
    docker exec -it kali bash

    # Consultar red
    docker network inspect cybernet

    # Inspeccionar variables de entorno de un contenedor
    docker inspect -f ‘{{range .Config.Env}}{{println .}}{{end}}’ mysql

    Retos

    1. Recon: desde kali hacer nmap -sV -p- --open 172.18.0.0/16 y documentar servicios.
    2. FTP-cred: conectarse a FTP (ftp user:ftpuser/ftp123) y buscar creds.txt.
    3. DB login: usar credenciales encontradas para entrar en MySQL (mysql -u admin -p admin123).
    4. SQLi: Explorar index.php y realizar un SQL injection básico para sacar datos o la flag.txt.
      • Ejemplo payload: '?user=admin' vs '?user=admin' OR '1'='1'
    5. Mail: desde web, forzar envío de correo a Maildev y ver en la UI :1080.
    6. Detección: activar logs/monitor y buscar patrones sospechosos (pings, intentos SQL).
    7. Hardening: cambiar la configuración, cerrar puertos, poner contraseñas robustas y documentar.