Seguridad PHP explicada · defensivo
XSS en PHP: qué es y cómo prevenirlo
El cross-site scripting sigue siendo uno de los fallos web más comunes. En PHP casi siempre se reduce a imprimir datos en HTML sin escaparlos para el lugar donde terminan.
Última actualización
Qué es
El XSS reflejado devuelve un valor de la petición actual; el XSS almacenado lo guarda, por ejemplo en un comentario, y lo sirve a todos; el XSS basado en DOM ocurre en el JavaScript del cliente. En todos los casos el navegador ejecuta script con los privilegios de su sitio, lo que permite robar sesiones o actuar como el usuario. MITRE lo clasifica como CWE-79.
Cómo detectarlo
- Busque en plantillas y archivos PHP
echo,printy<?=que impriman variables sinhtmlspecialchars()ni filtro de escape. - Preste especial atención a valores en atributos HTML, JavaScript en línea, URL y CSS, donde el escape HTML por sí solo no basta.
- Use las comprobaciones de seguridad de su framework y un escáner como OWASP ZAP contra una copia de staging propia.
Cómo corregirlo
- Escape al imprimir:
htmlspecialchars($v, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8')para el cuerpo HTML y atributos entre comillas. - Use un motor de plantillas con autoescape activado (Twig, Blade, Latte) y evite filtros de salida sin escapar para datos no confiables.
- Use
json_encode()conJSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOTpara datos en bloques script y valide las URL antes de ponerlas en href. - Añada una Content-Security-Policy y marque las cookies de sesión como HttpOnly, Secure y SameSite.
Comprobaciones de solo lectura y patrones seguros
# Find raw echo of request data (read-only, rough first pass)
grep -rnE "echo\s+\$_(GET|POST|REQUEST|COOKIE)" --include=*.php . | grep -v /vendor/
// Escape on output, for the HTML context
echo htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML5, 'UTF-8');
# Defense in depth: a Content-Security-Policy header (example)
Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'self'¿No es mejor quitar las etiquetas de la entrada?
Filtrar la entrada ayuda, pero lo que previene el XSS de forma fiable es escapar la salida según el contexto. OWASP recomienda primero la codificación de salida.
¿strip_tags() previene el XSS?
No de forma fiable. No cubre contextos de atributo ni de JavaScript y es fácil usarlo mal.
Otras clases de vulnerabilidades PHP
- Inyección de objetos PHP: qué es y cómo corregirlaLa inyección de objetos PHP ocurre cuando una entrada controlada por el usuario llega a unserialize(), que puede instanciar objetos cuyos métodos mágicos ejecutan la lógica que elige el atacante.
- Inclusión de archivos en PHP (LFI/RFI): qué es y cómo corregirlaLa inclusión de archivos ocurre cuando la entrada del usuario controla la ruta que recibe include o require, lo que permite leer archivos locales (LFI) o, con allow_url_include activado, ejecutar código remoto (RFI).
- SSRF en PHP: qué es y cómo corregirlaLa falsificación de peticiones del lado del servidor (SSRF) ocurre cuando una app PHP descarga una URL controlada por el usuario, lo que permite alcanzar servicios internos o endpoints de metadatos de la nube a través de su servidor.
- Exposición de phpinfo(): por qué importa y cómo corregirlaUna página phpinfo() pública revela la versión exacta de PHP, los módulos cargados, las rutas y a menudo variables de entorno o secretos, lo que ayuda a los atacantes a apuntar a fallos como PHP2Shell.
Fuentes
Los enlaces externos salen de este sitio. No alojamos código de explotación.
- CWE-79: Cross-site Scripting — MITRE CWE
- Cross Site Scripting Prevention Cheat Sheet — OWASP Cheat Sheet Series
- htmlspecialchars() — PHP Manual