Introducción a la seguridad en PHP (10 minutos)
Explicación:
La seguridad en PHP implica proteger aplicaciones web contra ataques que explotan vulnerabilidades, como datos de usuario no validados o consultas SQL inseguras. Dos prácticas fundamentales son la validación de entradas y la prevención de inyección SQL.
Conceptos clave:
- Validación de entradas:
- Verificar que los datos enviados por el usuario (por ejemplo, en formularios) sean válidos y seguros.
- Ejemplo: Asegurarse de que un campo de email contenga un formato válido (como usuario@dominio.com).
- Técnicas:
- Usar funciones PHP como filter_var() o trim().
- Comprobar longitud, tipo, y formato de los datos.
- Inyección SQL:
- Ataque donde un usuario inserta código SQL malicioso en un formulario para manipular la base de datos.
- Ejemplo: Un formulario vulnerable podría permitir borrar datos con una entrada como '; DROP TABLE usuarios; --.
- Prevención:
- Usar consultas preparadas con PDO o mysqli.
- Escapar datos con funciones como mysqli_real_escape_string().
- Por qué es importante:
- En Módulo 4, creaste formularios PHP que guardaban datos en MySQL (Módulo 5). Sin validación, estos son vulnerables.
- La seguridad es esencial en aplicaciones reales, como las desarrolladas con Laravel.
Punto clave: Validar entradas y prevenir inyección SQL protege los datos y la integridad de la aplicación.
Actividad rápida (2 minutos):
Escribe en papel un ejemplo de dato que debería validarse en un formulario.
- Ejemplo:
- Dato: Email.
- Validación: Comprobar formato (usuario@dominio.com).
Validación de entradas (10 minutos)
Explicación:
La validación de entradas asegura que los datos del usuario sean correctos y seguros antes de procesarlos. Esto incluye limpiar datos y verificar su formato.
Técnicas comunes:
- Limpiar datos:
- Eliminar espacios innecesarios con trim().
- Escapar caracteres especiales para HTML con htmlspecialchars() (evita ataques XSS).
- Ejemplo:
$nombre = trim($_POST['nombre']); $nombre = htmlspecialchars($nombre);
-
Validar formato:
- Usar filter_var() para validar tipos específicos (por ejemplo, email, entero).
- Ejemplo:
if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) { die("Email inválido"); }
-
Comprobar longitud y valores permitidos:
- Asegurarse de que un campo no esté vacío o sea demasiado largo.
- Ejemplo:
if (empty($_POST['nombre']) || strlen($_POST['nombre']) > 100) { die("Nombre inválido"); }
Por qué es importante:
- En Módulo 4, usaste $_POST directamente sin validación, lo que puede permitir datos maliciosos.
- La validación evita errores y ataques, como entradas vacías o mal formadas.
Punto clave: Validar y limpiar entradas es el primer paso para una aplicación segura.
Actividad rápida (2 minutos):
Escribe en papel una función PHP que usarías para validar un email.
- Ejemplo:
- Función: filter_var($email, FILTER_VALIDATE_EMAIL).
Prevención de inyección SQL (10 minutos)
Explicación:
La inyección SQL ocurre cuando un atacante inserta código SQL en un formulario para manipular la base de datos. La mejor defensa es usar consultas preparadas.
Cómo ocurre la inyección SQL:
- Ejemplo vulnerable (Módulo 4):
$email = $_POST['email']; $query = "SELECT * FROM usuarios WHERE email = '$email'"; // Si $email es: ' OR '1'='1 // Resultado: SELECT * FROM usuarios WHERE email = '' OR '1'='1' // Esto devuelve todos los usuarios (vulnerabilidad).
Prevención:
- Consultas preparadas:
- Usar PDO o mysqli para parametrizar consultas, evitando que los datos del usuario se interpreten como código SQL.
- Ejemplo con PDO:
$pdo = new PDO("mysql:host=localhost;dbname=app_usuarios", "root", ""); $stmt = $pdo->prepare("SELECT * FROM usuarios WHERE email = ?"); $stmt->execute([$_POST['email']]); $usuario = $stmt->fetch();
- Ejemplo con mysqli:
$conexion = new mysqli("localhost", "root", "", "app_usuarios"); $stmt = $conexion->prepare("SELECT * FROM usuarios WHERE email = ?"); $stmt->bind_param("s", $_POST['email']); $stmt->execute(); $resultado = $stmt->get_result();
- Escapar datos (si no usas consultas preparadas):
- Usar mysqli_real_escape_string() para escapar caracteres especiales.
- Ejemplo:
$email = $conexion->real_escape_string($_POST['email']); $query = "SELECT * FROM usuarios WHERE email = '$email'";
- Nota: Las consultas preparadas son preferibles, ya que son más seguras.
Por qué es importante:
- En Módulo 5, usaste consultas SQL para gestionar datos. Sin protección, son vulnerables.
- Las consultas preparadas son estándar en Laravel (Eloquent ORM).
Punto clave: Las consultas preparadas previenen la inyección SQL al separar datos y código.
Actividad rápida (2 minutos):
Escribe en papel una ventaja de usar consultas preparadas.
- Ejemplo:
- Ventaja: Evita que datos del usuario se interpreten como código SQL.
Ejemplo práctico: Escapa datos de un formulario antes de guardarlos (10 minutos)
Explicación:
Crearemos un formulario PHP que guarda un usuario (nombre y email) en una base de datos, aplicando validación de entradas y consultas preparadas para prevenir inyección SQL.
Escenario:
- Base de datos: app_usuarios con una tabla usuarios (creada en Módulo 5).
CREATE TABLE usuarios ( id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(100) NOT NULL, email VARCHAR(100) NOT NULL UNIQUE );
- Formulario: Permite registrar un usuario.
- Seguridad: Validar entradas y usar consultas preparadas.
Código del ejemplo:
- Formulario HTML (formulario.html):
<!DOCTYPE html> <html lang="es"> <head> <meta charset="UTF-8"> <title>Registrar Usuario</title> </head> <body> <h2>Registro de Usuario</h2> <form action="procesar.php" method="POST"> <label>Nombre: <input type="text" name="nombre"></label><br> <label>Email: <input type="email" name="email"></label><br> <button type="submit">Registrar</button> </form> </body> </html>
- Procesamiento PHP (procesar.php):
<?php // Validación de entradas $nombre = trim($_POST['nombre'] ?? ''); $email = trim($_POST['email'] ?? ''); if (empty($nombre) || strlen($nombre) > 100) { die("Error: El nombre es obligatorio y debe tener menos de 100 caracteres."); } if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { die("Error: El email no es válido."); } // Conexión a la base de datos $conexion = new mysqli("localhost", "root", "", "app_usuarios"); if ($conexion->connect_error) { die("Error de conexión: " . $conexion->connect_error); } // Consulta preparada para prevenir inyección SQL $stmt = $conexion->prepare("INSERT INTO usuarios (nombre, email) VALUES (?, ?)"); $stmt->bind_param("ss", $nombre, $email); // Ejecutar y verificar if ($stmt->execute()) { echo "Usuario registrado: $nombre ($email)"; } else { echo "Error al registrar: " . $conexion->error; } // Cerrar recursos $stmt->close(); $conexion->close(); ?>
Cómo probarlo:
- Asegúrate de que XAMPP o Laragon esté corriendo (Apache y MySQL).
- Crea la base de datos app_usuarios y la tabla usuarios en phpMyAdmin (http://localhost/phpmyadmin).
- Guarda formulario.html y procesar.php en C:\xampp\htdocs\seguridad (XAMPP) o C:\laragon\www\seguridad (Laragon).
- Abre http://localhost/seguridad/formulario.html (XAMPP) o http://seguridad.test/formulario.html (Laragon).
- Prueba el formulario:
- Válido: Nombre: “Ana”, Email: “ana@correo.com” → Mensaje: “Usuario registrado: Ana (ana@correo.com)”.
- Inválido: Nombre: vacío, Email: “no_es_email” → Mensaje de error.
- Usa DevTools (F12, pestaña “Red”):
- Verifica la solicitud POST a procesar.php.
- Código de estado: 200 OK (si es exitoso).
- Prueba una inyección SQL (por ejemplo, Email: '; DROP TABLE usuarios; --):
- La consulta preparada la neutraliza, evitando el ataque.
Por qué es importante:
- Este ejemplo mejora los formularios del Módulo 4 al añadir validación y seguridad.
- Prepara para Laravel, donde usarás validación (Validator) y Eloquent para consultas seguras.
Punto clave: Validar y escapar datos de un formulario protege contra ataques y errores.
Actividad rápida (3 minutos):
Escribe en papel una línea de código para validar un email en el ejemplo.
- Ejemplo:
- Línea: if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { die("Email inválido"); }.
5. Resumen y preparación para la tarea (5 minutos)
Resumen:
- Seguridad en PHP: Proteger aplicaciones contra ataques comunes.
- Validación de entradas: Limpiar y verificar datos con trim(), filter_var(), etc.
- Inyección SQL: Prevenirla con consultas preparadas (PDO o mysqli).
- Ejemplo: Formulario seguro que valida y guarda datos en la base de datos.
Preparación para la tarea:
La tarea pide añadir validación a un formulario PHP.
- Estrategia:
- Crea un formulario similar al del Módulo 4 (por ejemplo, registro de tareas).
- Valida entradas (por ejemplo, no vacías, formato correcto).
- Usa consultas preparadas para guardar datos en MySQL.
- Lógica básica:
- HTML: Formulario con campos (por ejemplo, título, descripción).
- PHP: Validar con filter_var(), trim(); usar mysqli_prepare().
- Prueba en XAMPP/Laragon.
Punto clave: La validación y las consultas preparadas son esenciales para aplicaciones PHP seguras.
Tarea práctica: Añade validación a un formulario PHP
Instrucciones:
- Crea un formulario PHP que guarde datos en una base de datos, basado en los proyectos del Módulo 4 o 5.
- Tema sugerido: Registro de tareas (título, descripción), pero puedes elegir otro (por ejemplo, registro de productos).
- Funcionalidad mínima: Recibir datos de un formulario, validarlos, y guardarlos en MySQL.
- Requisitos de seguridad:
- Validación de entradas:
- Asegurarse de que los campos no estén vacíos.
- Validar formatos (por ejemplo, longitud máxima, tipo de dato).
- Usar al menos trim() y htmlspecialchars().
- Prevención de inyección SQL:
- Usar consultas preparadas con mysqli o PDO.
- Validación de entradas:
- Estructura:
- Base de datos: Crea una tabla (por ejemplo, tareas).
- Formulario HTML: Campos para los datos (por ejemplo, título, descripción).
- Script PHP: Valida y guarda los datos.
- Entregable:
- Un archivo de texto o documento (tarea_seguridad.txt o .docx) con:
- Descripción del formulario (qué hace).
- SQL para la base de datos (por ejemplo, CREATE TABLE).
- Código HTML del formulario.
- Código PHP con validación y consulta preparada.
- Resultado de la prueba (por ejemplo, “Guardé una tarea correctamente”).
- Opcional: Captura de pantalla del formulario o resultado.
- Un archivo de texto o documento (tarea_seguridad.txt o .docx) con:
- Ejemplo de guía:
Tarea: Formulario seguro para registrar tareas Descripción: Un formulario PHP que guarda tareas (título, descripción) en una base de datos. Base de datos: CREATE DATABASE app_tareas; CREATE TABLE tareas ( id INT AUTO_INCREMENT PRIMARY KEY, titulo VARCHAR(200) NOT NULL, descripcion TEXT ); Formulario HTML (formulario.html): <form action="procesar.php" method="POST"> <label>Título: <input type="text" name="titulo"></label><br> <label>Descripción: <textarea name="descripcion"></textarea></label><br> <button type="submit">Guardar</button> </form> Script PHP (procesar.php): <?php $titulo = trim($_POST['titulo'] ?? ''); $descripcion = trim($_POST['descripcion'] ?? ''); if (empty($titulo) || strlen($titulo) > 200) { die("Error: Título obligatorio, máximo 200 caracteres."); } $conexion = new mysqli("localhost", "root", "", "app_tareas"); if ($conexion->connect_error) { die("Error de conexión: " . $conexion->connect_error); } $stmt = $conexion->prepare("INSERT INTO tareas (titulo, descripcion) VALUES (?, ?)"); $stmt->bind_param("ss", $titulo, $descripcion); if ($stmt->execute()) { echo "Tarea registrada: $titulo"; } else { echo "Error: " . $conexion->error; } $stmt->close(); $conexion->close(); ?> Resultado: Probé el formulario en Laragon (http://seguridad.test). Guardé una tarea con título “Estudiar PHP” y descripción “Capítulo 4”. Mensaje: “Tarea registrada: Estudiar PHP”.
- Pasos para completar:
- Paso 1: Diseña el formulario y la base de datos (usa phpMyAdmin).
- Paso 2: Crea el archivo HTML (formulario.html).
- Paso 3: Escribe el script PHP (procesar.php) con validación y consulta preparada.
- Paso 4: Prueba en XAMPP (http://localhost/seguridad) o Laragon (http://seguridad.test).
- Paso 5: Documenta el proceso en un archivo de texto o documento.
- Paso 6: Opcional: Incluye una captura de pantalla.
Ejemplo de solución esperada:
- Archivo (tarea_seguridad.txt):
Tarea: Formulario seguro para registrar tareas Descripción: Un formulario PHP que guarda tareas en una base de datos con validación y consultas preparadas. Base de datos: CREATE DATABASE app_tareas; CREATE TABLE tareas ( id INT AUTO_INCREMENT PRIMARY KEY, titulo VARCHAR(200) NOT NULL, descripcion TEXT ); Formulario HTML (formulario.html): <form action="procesar.php" method="POST"> <label>Título: <input type="text" name="titulo"></label><br> <label>Descripción: <textarea name="descripcion"></textarea></label><br> <button type="submit">Guardar</button> </form> Script PHP (procesar.php): <?php $titulo = trim($_POST['titulo'] ?? ''); $descripcion = trim($_POST['descripcion'] ?? ''); if (empty($titulo) || strlen($titulo) > 200) { die("Error: Título obligatorio, máximo 200 caracteres."); } $conexion = new mysqli("localhost", "root", "", "app_tareas"); if ($conexion->connect_error) { die("Error de conexión: " . $conexion->connect_error); } $stmt = $conexion->prepare("INSERT INTO tareas (titulo, descripcion) VALUES (?, ?)"); $stmt->bind_param("ss", $titulo, $descripcion); if ($stmt->execute()) { echo "Tarea registrada: $titulo"; } else { echo "Error: " . $conexion->error; } $stmt->close(); $conexion->close(); ?> Resultado: Probé en XAMPP (http://localhost/seguridad). Guardé una tarea: Título “Leer Módulo 6”, Descripción “Seguridad”. Mensaje: “Tarea registrada: Leer Módulo 6”.
Tiempo estimado: 45-60 minutos (puedes hacerlo después de la lección).
Entregable:
- Archivo de texto o documento con descripción, SQL, códigos HTML/PHP, y resultado.
- Opcional: Captura de pantalla.
Consejo:
- Usa el ejemplo como referencia para estructurar el formulario y el script.
- Prueba entradas inválidas (por ejemplo, título vacío, email mal formado) para verificar la validación.
- Revisa los logs de XAMPP/Laragon si encuentras errores (C:\xampp\apache\logs o C:\laragon\logs).