Introducción: ¿por qué su sitio en PHP podría ser hackeado ahora mismo?
\nImagine la situación: ha creado un sitio genial en PHP, un formulario de contacto, comentarios, un área personal. Todo funciona. Pero un día entra al panel de administración y está vacío. O peor aún: en el sitio aparece publicidad de un casino y Google ha bloqueado su recurso. ¿Le suena familiar? La raíz del mal es el procesamiento incorrecto de la entrada del usuario.
\nLa pregunta "How can I sanitize user input with PHP?" es una de las más populares en Stack Overflow. Miles de desarrolladores tropiezan una y otra vez con los mismos errores. En este artículo analizaremos los principales errores que cometen incluso los programadores experimentados y mostraremos cómo evitarlos. Aprenderá a protegerse contra XSS, inyecciones SQL y otros ataques. ¡Allá vamos!
\n\nError n.º 1: Usar mysql_real_escape_string() para todo
\nLa vieja escuela: muchos desarrolladores todavía piensan que si envuelven todos los datos en mysql_real_escape_string(), el problema está resuelto. Esto es un grave error. Esta función está diseñada solo para escapar cadenas en consultas SQL, y además para la extensión obsoleta mysql_*, que se eliminó ya en PHP 7.
Ejemplo de código incorrecto:
\n<?php\n$name = mysql_real_escape_string($_POST['name']);\n$query = "INSERT INTO users (name) VALUES ('$name')";\n$result = mysql_query($query);\n?>\nPor qué es malo:
\n- \n
- La función no protege contra ataques XSS (por ejemplo, inserción de JavaScript). \n
- La extensión
mysql_*está obsoleta y no es segura. \n - Se mezcla la lógica de escape con la lógica de negocio. \n
Cómo solucionarlo: use consultas preparadas (prepared statements) con PDO o MySQLi. Y para mostrar datos en pantalla, use una sanitización independiente.
\n\nError n.º 2: Ignorar los ataques XSS al mostrar datos
\nEl error más común. Recibe datos, los guarda en la base de datos y simplemente los muestra con echo o print. Voilà: un atacante puede insertar un script que robe cookies, redirija al usuario o dañe el diseño.
Ejemplo de código vulnerable:
\n<?php\necho "<p>Hola, " . $_GET['name'] . "!</p>";\n?>\nSi en la URL se pasa ?name=<script>alert('XSS')</script>, el script se ejecutará.
Solución: use la función htmlspecialchars() con el parámetro ENT_QUOTES:
<?php\n$name = htmlspecialchars($_GET['name'], ENT_QUOTES, 'UTF-8');\necho "<p>Hola, " . $name . "!</p>";\n?>\nImportante: la sanitización debe hacerse justo en el momento de la salida, no al guardar. Si reemplaza caracteres en la base de datos, perderá los datos originales.
\n\nError n.º 3: Filtrado ciego con strip_tags()
\nMuchos piensan: "Oh, simplemente eliminaré todas las etiquetas HTML y listo". Pero strip_tags() no es una panacea. Primero, solo elimina etiquetas, pero deja los atributos (por ejemplo, onclick). Segundo, si necesita permitir algunas etiquetas (como <b> o <i>), strip_tags() se vuelve incómodo.
Ejemplo:
\n<?php\n$comment = strip_tags($_POST['comment']);\necho $comment; // Eliminará <script>, pero dejará <a onclick="...">\n?>\nSolución: use htmlspecialchars() para texto normal o bibliotecas como HTML Purifier si necesita permitir ciertas etiquetas. HTML Purifier verifica no solo etiquetas, sino también atributos, estilos e incluso CSS.
Error n.º 4: Falta de validación de email, URL y números
\nLa sanitización no es solo sobre XSS. Si espera un email y recibe la cadena "123", puede causar errores. O si guarda una URL sin verificar, un atacante puede insertar javascript:alert(1).