M1 · Bloque I Introducción Variables y tipos Operadores Estructuras de control Funciones y ámbito Arrays y objetos Depuración Ejercicios Resumen
Nivel 1 Bloque I — Programación y fundamentos Gratuito

M1 · Fundamentos de
programación

Antes de PHP, antes de WordPress, antes de cualquier vulnerabilidad: necesitas entender cómo piensa un ordenador. Variables, operadores, bucles y funciones son los bloques con los que se construye cualquier programa — y también con los que se construyen la mayoría de las vulnerabilidades.

Al finalizar este módulo serás capaz de:

  • Declarar y manipular variables de distintos tipos de datos
  • Aplicar operadores aritméticos, lógicos y de comparación correctamente
  • Controlar el flujo de un programa con condicionales y bucles
  • Crear funciones reutilizables con parámetros, retorno y ámbito correcto
  • Trabajar con arrays indexados, asociativos y multidimensionales
  • Depurar código identificando y corrigiendo errores comunes

¿Por qué empezar por aquí?

Una vulnerabilidad de inyección SQL no existe porque MySQL sea inseguro. Existe porque un programador concatenó una variable directamente en una consulta sin validarla. Un XSS no existe porque JavaScript sea peligroso. Existe porque el código imprimió datos del usuario sin escaparlos.

La mayoría de las vulnerabilidades son errores de programación. Y para identificarlos — y explotarlos o prevenirlos — necesitas pensar como un programador. Este módulo te da esa base.

Lenguaje de referencia: PHP

Usamos PHP porque es el lenguaje de WordPress. Pero los conceptos — variables, bucles, funciones — son universales. Si los aprendes aquí, entenderás Python, JavaScript o cualquier otro lenguaje sin dificultad.

Guardar información

Las variables son contenedores que guardan datos en memoria. $nombre = "Ana" reserva espacio y etiqueta el valor.

Tomar decisiones

Los condicionales ejecutan código solo si se cumple una condición. if ($edad >= 18) es una bifurcación lógica.

Repetir acciones

Los bucles ejecutan el mismo bloque múltiples veces. foreach ($plugins as $p) recorre una lista completa.

Reutilizar código

Las funciones agrupan instrucciones bajo un nombre. sanitizar($input) puede usarse miles de veces sin reescribir.

Variables y tipos de datos

Una variable es un nombre que apunta a un valor en memoria. En PHP todas empiezan por $. PHP es de tipado dinámico: infiere el tipo según el valor asignado, lo cual es cómodo pero fuente de vulnerabilidades si no se controla.

PHP — tipos básicos
// INTEGER — números enteros
$edad     = 25;
$puerto   = 8080;
$negativo = -42;

// FLOAT — decimales
$precio   = 99.99;

// STRING — texto
$nombre   = "SecurityWP";
$ruta     = '/var/www/html';

// BOOLEAN — verdadero o falso
$activo   = true;
$admin    = false;

// NULL — ausencia de valor
$resultado = null;

// Verificar tipo
var_dump($edad);    // int(25)
gettype($nombre);  // "string"
TipoEjemploUso habitualRiesgo de seguridad
int42IDs, puertos, contadoresVerificar rangos positivos
float3.14Precios, métricasComparaciones imprecisas
string"admin"Nombres, SQL, HTMLEl tipo más peligroso sin sanitizar
booltrueFlags, permisosCoerciones inesperadas con ==
nullnullValores ausentesComportamientos inesperados
array[1,2,3]Listas, configsType juggling en comparaciones

Type juggling — el mayor peligro de PHP

PHP convierte tipos automáticamente al comparar con ==. Esto ha causado vulnerabilidades reales de bypass de autenticación en producción:

PHP — type juggling peligroso
// Con == PHP convierte tipos antes de comparar
0    == "hola"      // true  ← 0 == cualquier string no numérico
1    == "1abc"     // true  ← "1abc" se convierte a 1
true  == "cualquier" // true
false == ""          // true
null  == false       // true
100   == "1e2"       // true  ← notación científica

// VULNERABILIDAD REAL — bypass de login con hash mágico
$hash_guardado = "0e123456789";  // hash MD5 "mágico"
$hash_enviado  = "0e987654321";  // otro hash "mágico"

if ($hash_guardado == $hash_enviado) {  // true ← ambos = 0^e = 0
    // BYPASS: acceso concedido sin contraseña correcta
}

// SOLUCIÓN: usar siempre === (idéntico: mismo valor Y mismo tipo)
if ($hash_guardado === $hash_enviado) {  // false ← correcto
    // Acceso correcto
}
Regla de oro — siempre ===

Usa siempre === (tres iguales) para comparar en PHP. El operador == convierte tipos antes de comparar y ha causado vulnerabilidades de autenticación reales en aplicaciones de producción. Aplica especialmente al comparar hashes, tokens y contraseñas.

Operadores

Los operadores combinan variables y valores para producir un resultado. Son la base de toda lógica de programa.

PHP — operadores esenciales
// ── ARITMÉTICOS ────────────────────────────────────
$a = 10; $b = 3;
$suma     = $a + $b;   // 13
$resta    = $a - $b;   // 7
$producto = $a * $b;   // 30
$division = $a / $b;   // 3.33...
$modulo   = $a % $b;   // 1 ← útil para paginación y paridad
$potencia = $a ** $b;  // 1000
$a++;  $a--;             // incremento / decremento
$a += 5; $a .= " texto"; // asignación compuesta

// ── COMPARACIÓN (siempre usa ===) ──────────────────
$a === $b  // idéntico: mismo valor Y tipo ← USAR ESTO
$a !== $b  // no idéntico ← USAR ESTO
$a ==  $b  // igual con conversión ← EVITAR
$a >   $b  // mayor que
$a >=  $b  // mayor o igual
$a <=> $b  // spaceship: -1, 0 o 1 (para ordenar)

// ── LÓGICOS ────────────────────────────────────────
$a && $b   // AND: ambos true
$a || $b   // OR: al menos uno true
!$a         // NOT: invierte

// ── STRINGS ────────────────────────────────────────
$completo = "Security" . "WP";          // concatenación con punto
$saludo   = "Hola, {$nombre}";            // interpolación
htmlspecialchars($input, ENT_QUOTES);     // escapar HTML ← fundamental

// ── NULL COALESCING ─────────────────────────────────
$nombre = $_POST['nombre'] ?? 'Anónimo'; // si no existe usa default

Estructuras de control

Las estructuras de control determinan qué código se ejecuta y cuántas veces. Son la lógica central del programa.

Condicionales

PHP — if / elseif / else / match
// Control de acceso por rol
$rol = "editor";

if ($rol === "admin") {
    echo "Acceso completo";
} elseif ($rol === "editor") {
    echo "Puede editar contenido";
} else {
    echo "Sin acceso";
    exit;
}

// Operador ternario — forma corta
$msg = ($rol === "admin") ? "Admin" : "Usuario";

// match (PHP 8) — más seguro que switch, usa ===
$tipo = match($_SERVER['REQUEST_METHOD']) {
    'GET'            => 'lectura',
    'POST'           => 'escritura',
    'DELETE', 'PUT'  => 'modificación',
    default          => 'desconocido',
};

Bucles

PHP — for / while / foreach
// FOR — cuando sabes cuántas iteraciones
for ($i = 0; $i < 10; $i++) {
    echo "Intento {$i}\n";
}

// WHILE — mientras se cumpla una condición
$intentos = 0;
while ($intentos < 5) {
    // lógica...
    $intentos++;
}

// FOREACH — recorrer arrays (el más usado en WordPress)
$plugins = ['woocommerce', 'yoast', 'elementor'];
foreach ($plugins as $plugin) {
    echo "Analizando: {$plugin}\n";
}

// FOREACH con clave => valor
$vulns = ['CVE-2025-1234' => 'crítico', 'CVE-2025-5678' => 'alto'];
foreach ($vulns as $cve => $severidad) {
    echo "{$cve}: {$severidad}\n";
}

// break y continue
foreach ($plugins as $plugin) {
    if ($plugin === 'inactivo') continue; // saltar
    if ($plugin === 'malware')  break;    // parar todo
}
Bucles infinitos

Un while(true) sin salida bloqueará el proceso PHP y puede causar un DoS involuntario en producción. Asegúrate siempre de que el bucle tiene una condición de salida garantizada.

Funciones y ámbito

Una función es un bloque de código con nombre que puedes reutilizar. Son la piedra angular del código limpio y seguro: en lugar de copiar-pegar validaciones por todo el código, creas una función validar_email() y la llamas donde la necesites.

PHP — funciones
// Definición básica
function saludar($nombre) {
    return "Hola, {$nombre}";
}
echo saludar("Ana");  // "Hola, Ana"

// Parámetros por defecto
function conectar($host = 'localhost', $puerto = 3306) {
    return "{$host}:{$puerto}";
}

// Tipos declarados (PHP 7+) — más seguro
function sanitizar(string $valor, int $max = 255): string {
    $valor = trim($valor);
    $valor = strip_tags($valor);
    $valor = mb_substr($valor, 0, $max);
    return htmlspecialchars($valor, ENT_QUOTES | ENT_HTML5, 'UTF-8');
}

// ÁMBITO: las variables dentro no salen fuera
$secreto = "clave_api_xyz";

function mal_ejemplo() {
    // $secreto NO existe aquí — ámbito diferente
    // necesitarías: global $secreto; ← evitar globals
}

// Arrow functions (PHP 7.4+) — capturan ámbito automáticamente
$multiplicar = fn($x, $y) => $x * $y;
echo $multiplicar(3, 4);  // 12

// Pasar función como argumento
$numeros = [3, 1, 4, 1, 5];
usort($numeros, fn($a, $b) => $a <=> $b);
Principio de responsabilidad única

Cada función debe hacer una sola cosa y hacerla bien. validar_y_guardar_y_enviar_email() es una señal de alerta. Separa: validar(), guardar(), notificar(). El código seguro es código legible y auditable.

Arrays y objetos

Los arrays son la estructura de datos más usada en PHP y en WordPress. La base de datos devuelve arrays, los posts son arrays, las opciones de WordPress son arrays. Dominarlos es imprescindible.

PHP — arrays completo
// Array indexado
$plugins = ['woocommerce', 'yoast', 'elementor'];
$plugins[0];       // 'woocommerce'
$plugins[] = 'akismet'; // añadir al final

// Array asociativo (clave => valor)
$usuario = [
    'id'     => 42,
    'nombre' => 'Ana García',
    'email'  => 'ana@ejemplo.com',
    'rol'    => 'editor',
];
$usuario['nombre'];          // 'Ana García'
$usuario['rol'] = 'admin'; // modificar

// Array multidimensional
$vulns = [
    ['cve' => 'CVE-2025-1234', 'sev' => 'crítico'],
    ['cve' => 'CVE-2025-5678', 'sev' => 'alto'],
];
$vulns[0]['cve'];  // 'CVE-2025-1234'

// Funciones esenciales
count($plugins);                        // número de elementos
in_array('yoast', $plugins, true);     // ¿existe? (estricto)
array_key_exists('email', $usuario);    // ¿existe la clave?
array_map('trim', $plugins);            // aplicar función a cada elemento
array_filter($plugins, fn($p) => strlen($p) > 5); // filtrar
array_merge($plugins, ['nuevo']);       // combinar

// LISTA BLANCA — patrón de seguridad fundamental
$permitidos = ['auditoria', 'mantenimiento', 'consultoria'];
$servicio   = $_POST['servicio'] ?? '';

if (!in_array($servicio, $permitidos, true)) {
    die('Servicio no válido');  // 3er param true = comparación estricta
}

Introducción a objetos

PHP — clase básica
class Auditoria {
    private string $url;
    private array  $vulns = [];

    public function __construct(string $url) {
        $this->url = $url;
    }

    public function agregar(string $cve, string $sev): void {
        $this->vulns[] = ['cve' => $cve, 'sev' => $sev];
    }

    public function resumen(): string {
        $total = count($this->vulns);
        return "{$this->url}: {$total} vulnerabilidades";
    }
}

$audit = new Auditoria('https://ejemplo.com');
$audit->agregar('CVE-2025-1234', 'crítico');
echo $audit->resumen();  // "https://ejemplo.com: 1 vulnerabilidades"

Depuración básica

Depurar es encontrar y corregir errores. En seguridad, la depuración también significa entender qué hace realmente el código, no solo qué se supone que debería hacer. Es una habilidad crítica al auditar plugins de WordPress.

Tipo de errorEjemploConsecuencia
Parse ErrorFalta un ; o }El script no arranca
Fatal ErrorLlamar función inexistenteEl script se detiene
WarningIncluir archivo inexistenteContinúa pero con problemas
NoticeUsar variable no definidaContinúa — potencialmente inseguro
Logic ErrorAlgoritmo incorrectoSin error visible pero resultado incorrecto
PHP — herramientas de depuración
// var_dump — muestra tipo Y valor
$datos = ['user' => 'admin', 'pass' => '1234'];
var_dump($datos);
// array(2) { ["user"]=> string(5) "admin" ["pass"]=> string(4) "1234" }

// print_r — más legible para arrays
print_r($datos);

// Parar ejecución en un punto (inspeccionar estado)
var_dump($variable_sospechosa); die('STOP');

// Error reporting en desarrollo — SOLO en local
error_reporting(E_ALL);
ini_set('display_errors', '1');  // NUNCA en producción

// Logs en lugar de pantalla (producción)
error_log('[SecurityWP] Error: ' . $mensaje);
// Escribe en el error_log del servidor

// Activar WP_DEBUG para auditar plugins de WordPress
// En wp-config.php:
define('WP_DEBUG',         true);
define('WP_DEBUG_LOG',     true);   // guarda en /wp-content/debug.log
define('WP_DEBUG_DISPLAY', false);  // no mostrar en pantalla
Depuración como técnica de análisis de seguridad

Al auditar un plugin de WordPress, var_dump() y error_log() te permiten entender qué valores llegan a cada función y detectar inputs no validados. Activa WP_DEBUG = true en el entorno de desarrollo para ver todos los errores y notices.

Ejercicios prácticos

01

Detectar type juggling

~20 min

Crea un archivo PHP en local y prueba estas comparaciones con == y con ===. Anota los resultados que te sorprendan y razona por qué ocurren.

PHP — experimento
$casos = [[0,"hola"],[true,"1"],[null,""],[false,"0"],[100,"1e2"]];
foreach ($casos as [$a, $b]) {
    $laxa    = ($a ==  $b) ? 'true' : 'false';
    $estricta = ($a === $b) ? 'true' : 'false';
    printf("%s == %s → %s | === → %s\n",
        var_export($a,true), var_export($b,true), $laxa, $estricta);
}
02

Función de validación de contraseña

~30 min

Escribe la función validar_password(string $pass): array que devuelva un array con los errores encontrados. Si el array está vacío, la contraseña es válida.

03

Analizador de plugins desactualizados

~45 min

Dado el array de plugins con versión instalada y versión actual, escribe código que identifique los desactualizados e imprima un informe ordenado por urgencia.

PHP — datos de partida
$plugins = [
    ['nombre'=>'WooCommerce',   'instalada'=>'8.3.0', 'actual'=>'8.5.1'],
    ['nombre'=>'Yoast SEO',      'instalada'=>'22.1',  'actual'=>'22.1'],
    ['nombre'=>'Contact Form 7', 'instalada'=>'5.7.0', 'actual'=>'5.9.2'],
    ['nombre'=>'Elementor',      'instalada'=>'3.19.0','actual'=>'3.21.0'],
];

Resumen y siguiente módulo

Variables y tipos

  • Tipos: int, float, string, bool, null
  • Tipado dinámico → type juggling peligroso
  • Usar siempre === para comparar

Operadores

  • Aritméticos: + - * / % **
  • Comparación estricta: === !==
  • Lógicos: && || !
  • Null coalescing: ??

Control de flujo

  • if / elseif / else
  • match (PHP 8, usa ===)
  • for / while / foreach
  • break / continue

Funciones y arrays

  • Tipos declarados en parámetros y retorno
  • Arrays indexados, asociativos y multidim.
  • Lista blanca con in_array(..., true)
  • var_dump y error_log para debug
Siguiente: M2 · PHP — Lenguaje del servidor

Profundizamos en PHP: superglobales ($_POST, $_GET, $_SERVER), manejo de errores con excepciones, programación orientada a objetos completa y Composer. Todo con foco en las implicaciones de seguridad de cada concepto.


Ir al Módulo 2 →
Volver al programa
Módulo 1 de 20