Tu código PHP en la mira: por qué el silencio no es oro
\n\nImagina esto: lanzas tu sitio web, todo funciona a la perfección, tus clientes están contentos. Mientras tanto, en algún rincón oscuro de internet, un script kiddie escribe en tu formulario de búsqueda la mágica cadena ' OR 1=1 --. Y la base de datos, como un sirviente obediente, le entrega todas las contraseñas de los usuarios. ¿Te suena familiar? Lamentablemente, para muchos desarrolladores principiantes, sí.
La seguridad en PHP no es una burocracia aburrida, es la protección real de tu tiempo, dinero y reputación. Hoy vamos a analizar a los dos principales enemigos de las aplicaciones web: las inyecciones SQL y el cross-site scripting (XSS). Aprenderás a identificarlos, neutralizarlos y nunca más permitirlos en tu código.
\n\nInyecciones SQL: cuando el usuario se convierte en hacker
\n\nUna inyección SQL es un ataque en el que un atacante «inyecta» código SQL malicioso a través de campos de entrada. Si simplemente insertas los datos del usuario en una consulta, es como si le abrieras la puerta al ladrón tú mismo.
\n\nCómo se ve un código vulnerable
\n\nAquí tienes un ejemplo clásico que todavía se encuentra en libros antiguos y en sitios web reales:
\n\n<?php\n// ¡PELIGROSO! Nunca hagas esto\n$username = $_POST['username'];\n$password = $_POST['password'];\n\n$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";\n$result = mysqli_query($conn, $query);\n?>\n\n¿Qué sucede si en el campo username escribes admin' --? La consulta se convierte en:
SELECT * FROM users WHERE username = 'admin' --' AND password = ''\n\nEl doble guión -- comenta el resto de la consulta. ¡Listo! El atacante ingresa como administrador sin contraseña. ¿Y si escribe '; DROP TABLE users; --? Adiós, usuarios.
El salvavidas: Consultas preparadas (Prepared Statements)
\n\nLa mejor forma de protegerte contra las inyecciones SQL es usar consultas preparadas con PDO o MySQLi. Estas separan la lógica de la consulta de los datos, por lo que el código malicioso nunca se ejecutará.
\n\nAsí se ve un código seguro con PDO:
\n\n<?php\n// ¡SEGURO! Usamos consultas preparadas\n$username = $_POST['username'];\n$password = $_POST['password'];\n\n$stmt = $pdo->prepare("SELECT * FROM users WHERE username = :username AND password = :password");\n$stmt->execute(['username' => $username, 'password' => $password]);\n$user = $stmt->fetch();\n?>\n\nAhora, incluso si el atacante envía admin' OR 1=1 --, PDO lo tratará como una cadena de texto normal, no como parte de un comando SQL. La base de datos dirá: «Buscando un usuario con ese nombre tan extraño». Y no lo encontrará.
¿Por qué PDO y no mysql_*?
\n\n- \n
- Seguridad por defecto: PDO escapa los datos automáticamente. \n
- Flexibilidad: soporta diferentes bases de datos (MySQL, PostgreSQL, SQLite). \n
- Placeholders con nombre: el código es más legible y fácil de mantener. \n
- Enfoque orientado a objetos: un estilo de programación moderno. \n
Las funciones mysql_* se eliminaron en PHP 7.0, y fue para bien. Si todavía usas mysqli_real_escape_string, es mejor que nada, pero PDO sigue siendo más fiable.
Ataques XSS: cuando el código se esconde en los comentarios
\n\nEl cross-site scripting (XSS) es la inserción de código JavaScript en una página a través de la entrada del usuario. Imagina que un usuario deja un comentario, pero en lugar de texto escribe:
\n\n<script>alert('¡Tu sitio ha sido hackeado!');</script>\n\nSi muestras esto sin procesar, cada visitante verá una ventana emergente. ¿Y si en lugar de alert hubiera un código que robe cookies o redirija a un sitio de phishing?
Tipos de ataques XSS
\n\n- \n
- Reflejado (Reflected): el código malicioso