HOWTO · PHP
Desinfectar la entrada en PHP
En la publicación de hoy, aprenderemos cómo desinfectar los datos de entrada en PHP antes de pasarlos a la base de datos.
En esta página
No existe un paso universal que vuelva seguro cualquier valor no confiable. Determina qué representa el valor, valídalo según ese requisito, normalízalo solo si la aplicación tiene una regla clara para hacerlo, codifícalo para el contexto en el que se mostrará y usa consultas parametrizadas al enviarlo a una base de datos. Estas operaciones resuelven problemas distintos: la validación acepta o rechaza un valor, la desinfección lo transforma y la codificación de salida representa los caracteres de forma segura para un contexto específico. Ninguna de ellas, por sí sola, garantiza la integridad de los datos ni protege todos los usos de un valor.
Qué puede y qué no puede hacer la desinfección de entradas en PHP
El tratamiento de las entradas empieza por definir el contrato de cada campo. La edad, la dirección de correo electrónico, el nombre para mostrar y un término de búsqueda tienen distintos formatos válidos. La validación comprueba si un valor cumple ese contrato; la normalización aplica una transformación intencionada y documentada, como quitar los espacios de alrededor. Un desinfectante puede quitar o transformar caracteres, pero eso podría cambiar silenciosamente lo que envió el usuario y no hace que el resultado sea adecuado para cualquier uso posterior.
Si la aplicación necesita conservar el valor original, mantenlo separado de cualquier representación normalizada o codificada. No elimines caracteres solo porque parezcan inusuales: los nombres y otros textos legítimos pueden contener signos de puntuación o caracteres no ASCII. Elige también el tratamiento en el punto de uso. La salida HTML necesita codificación HTML, mientras que los valores SQL necesitan parámetros de consulta. Estas protecciones no son intercambiables.
Escapar HTML al mostrar entradas del usuario
Codifica el texto al insertarlo en un nodo de texto HTML o en un atributo entre comillas. Para la salida HTML habitual, htmlspecialchars() convierte los caracteres con significado en HTML, incluidos los ampersands, los signos de menor y mayor que y las comillas cuando se usan las opciones adecuadas. htmlentities() también codifica los caracteres que tienen entidades HTML con nombre. Ninguna de las dos funciones es un desinfectante HTML de propósito general: codificar un valor para un nodo de texto no lo vuelve seguro para insertarlo en JavaScript, CSS, una URL o marcado HTML sin procesar. Usa el codificador y las reglas correspondientes al contexto de salida exacto.
Este ejemplo autocontenido codifica un nombre para un nodo de texto HTML:
El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.
<?php
$name = 'Ada & Sam';
echo htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'), PHP_EOL;
Ada & Sam
La evidencia de ejecución proporcionada confirma esta salida. Es una cadena destinada a un contexto de texto HTML, no un valor que deba reutilizarse en SQL o JavaScript.
Validar y normalizar entradas con filter_var()
filter_var() aplica una operación de validación o filtrado seleccionada; no es un desinfectante HTML. Por ejemplo, filter_var($email, FILTER_VALIDATE_EMAIL) devuelve la dirección de correo aceptada o false si no coincide con el filtro. filter_var($count, FILTER_VALIDATE_INT) puede validar un entero, con opciones disponibles cuando la aplicación necesita un rango específico. Comprueba explícitamente el valor devuelto, ya que false indica que la validación ha fallado.
Los filtros de desinfección pueden transformar la entrada en vez de demostrar que es válida. Por ejemplo, FILTER_SANITIZE_EMAIL elimina los caracteres que ese filtro no permite; no demuestra que la dirección resultante pertenezca a un usuario ni que pueda recibir correo. Si la aplicación decide normalizar la entrada, define la regla y luego valida el resultado. Evita depender de FILTER_SANITIZE_STRING como solución general: eliminar marcado no proporciona una codificación de salida adecuada para cada contexto ni vuelve seguro cualquier contenido.
Usar sentencias preparadas para SQL
Usa consultas parametrizadas para mantener la sintaxis SQL separada de los valores proporcionados por el usuario. Con PDO, prepara una consulta con un marcador de posición y pasa el valor por separado al ejecutarla. Por ejemplo, el patrón es $statement = $pdo->prepare('SELECT id, email FROM Users WHERE lastname = :lastname');, seguido de $statement->execute(['lastname' => $lastname]);. Este es un fragmento ilustrativo: $pdo ya debe estar conectado a la base de datos prevista; el servicio de base de datos y el esquema quedan fuera del ejemplo.
PDO no desinfecta entradas arbitrarias. Para los valores de la consulta, la vinculación de parámetros es la protección contra la inyección SQL; no valida que un valor tenga sentido para la aplicación. Valida los valores según las reglas de sus campos y emplea una estrategia distinta para construir consultas con identificadores como nombres de tablas o columnas, que por lo general no se pueden suministrar como parámetros de valor. MySQLi también admite sentencias preparadas; usa su API de vinculación de parámetros al trabajar con esa interfaz.
Tratar los campos del perfil según el tipo que se espera
Aplica una regla distinta a cada campo del perfil. Valida una dirección de correo y, si hace falta, confirma que el usuario la controla mediante un flujo de la aplicación; quita los espacios de un nombre para mostrar solo si esa es la política prevista; valida un código postal según la región correspondiente, en vez de asumir que existe un formato universal. Para un campo numérico, analiza el valor y comprueba que esté dentro del rango permitido antes de usarlo. Conserva los signos de puntuación legítimos y los caracteres Unicode cuando el campo lo permita.
Al mostrar en una página valores de perfil almacenados, codifícalos en el momento de la salida para el contexto HTML específico, aunque se hayan validado al enviarse. Al consultar un perfil, pasa los valores mediante sentencias preparadas. Mantener la validación, la normalización, la parametrización de la consulta y la codificación de salida como decisiones separadas facilita razonar sobre el tratamiento y evita confundir una transformación con una protección universal.