Subidas de archivos seguras en aplicaciones PHP y WordPress: guía práctica
Los formularios de subida son una vía común de entrada a sitios PHP. Cinco hábitos los protegen: tipos permitidos, almacenamiento seguro, sin ejecución de scripts, límites y análisis.
Un formulario de subida de archivos es una de las entradas más fáciles a un sitio web en PHP cuando está mal construido, porque un atacante que logra subir un archivo .php y luego abrirlo en el navegador puede ejecutar su propio código en su servidor. Las subidas seguras se apoyan en cinco hábitos: aceptar solo los tipos de archivo que necesita y comprobar su contenido real, renombrar los archivos y guardarlos fuera de la raíz web (o al menos donde no puedan ejecutarse scripts), bloquear la ejecución de scripts en cualquier carpeta de subidas, fijar límites de tamaño en el servidor y analizar lo que llega. Esta guía cubre cada uno para aplicaciones PHP a medida y para WordPress, en términos que un gerente de oficina puede usar al hablar con su desarrollador o proveedor de hosting.
Por qué las subidas son riesgosas
Los formularios de contacto con adjuntos, la recepción de currículums, los portales de documentos para clientes y la biblioteca de medios de WordPress aceptan archivos desde fuera. Lo que puede salir mal:
- Web shells: un archivo PHP disfrazado de imagen (
factura.pdf.php, o una imagen real con código PHP dentro) se guarda en una carpeta pública y se ejecuta. - Documentos maliciosos: un archivo de Office o un PDF inofensivo para el servidor pero peligroso para el empleado que lo abre.
- Abuso de recursos: archivos enormes o numerosos que llenan el disco o la memoria.
- Trucos con rutas: un nombre como
../../config.phpque intenta escribir fuera de la carpeta de subidas.
1. Permita solo los tipos que necesita y compruebe el contenido
Decida exactamente qué formatos necesita el formulario (por ejemplo PDF, JPG y PNG) y rechace todo lo demás. Use una lista de permitidos, no una lista de bloqueados; OWASP señala que las listas de bloqueo son fáciles de eludir.
No confíe en lo que dice el navegador. El manual de PHP es claro: $_FILES['…']['type'] no se verifica del lado de PHP, porque lo controla por completo el cliente. En su lugar:
- Compruebe la extensión contra su lista de permitidos.
- Detecte el tipo real a partir del contenido del archivo en el servidor, por ejemplo con
finfode PHP (FILEINFO_MIME_TYPE), y asegúrese de que coincide con la extensión. - En el caso de las imágenes, volver a procesarlas (guardarlas de nuevo con GD o Imagick al mismo tamaño o menor) elimina la mayoría de las cargas ocultas.
OWASP añade que la verificación de la firma del archivo no debe usarse por sí sola, y por eso los siguientes pasos importan igual.
En WordPress
WordPress compara las subidas con una lista de tipos de archivo permitidos e intenta detectar el tipo real a partir del contenido (wp_check_filetype_and_ext). Conserve esa protección:
- No defina
ALLOW_UNFILTERED_UPLOADSenwp-config.php. Permite que los usuarios con la capacidadunfiltered_uploadse salten la verificación de tipos. - Tenga cuidado con los plugins que "permiten cualquier tipo de archivo" o que habilitan la subida de SVG sin sanearlos.
- Limite quién puede subir archivos: asigne al personal el rol más bajo que le permita hacer su trabajo y revise los plugins de formularios que aceptan adjuntos del público.
2. Renombre los archivos y guárdelos de forma segura
- Genere usted el nombre con el que se guarda (por ejemplo un identificador aleatorio) y conserve el nombre original solo en la base de datos para mostrarlo. OWASP recomienda cambiar el nombre del archivo por uno generado por la aplicación.
- Elimine las partes de directorio de cualquier nombre que sí use; el ejemplo del manual de PHP usa
basename()para ayudar a evitar el recorrido de rutas (path traversal). - Use
move_uploaded_file(), que solo mueve archivos realmente subidos desde la carpeta temporal de PHP. - Guarde los archivos fuera de la raíz web cuando pueda, como
/home/site/private-uploads/, y entréguelos mediante un script que compruebe que el usuario tiene permiso para ver ese archivo. Así deberían servir los portales de clientes las facturas, contratos e identificaciones. - Asigne permisos restrictivos a los archivos guardados (sin permiso de ejecución).

3. Bloquee la ejecución de scripts en las carpetas de subidas
Algunas subidas tienen que ser públicas, como las imágenes de la biblioteca de medios de WordPress (wp-content/uploads). En esas carpetas, asegúrese de que el servidor web nunca ejecute PHP, aunque se cuele un archivo .php.
Nginx (dentro del bloque server del sitio, antes de la regla general de PHP):
location ~* ^/wp-content/uploads/.*\.(php|phar|phtml)$ {
deny all;
}
Apache (un .htaccess en la carpeta de subidas o, mejor aún, en la configuración principal):
<FilesMatch "\.(php|phar|phtml)$">
Require all denied
</FilesMatch>
OWASP también recomienda desactivar las configuraciones por directorio (como .htaccess) en las carpetas de subidas, para que un archivo de configuración subido no pueda cambiar estas reglas. En Apache, eso significa AllowOverride None para la ruta de subidas en la configuración principal.
Del lado de PHP-FPM, configure security.limit_extensions = .php para que FPM se niegue a ejecutar cualquier archivo que no sea .php, y ejecute cada sitio con su propio usuario del sistema para que una subida exitosa no alcance a otros sitios.
Después de aplicar la regla, pruébela: coloque un archivo .php de prueba inofensivo en la carpeta de subidas, confirme que el navegador recibe "403 Forbidden" en lugar de ejecutarlo y luego borre el archivo.
4. Fije límites de tamaño en el servidor
Los límites en el navegador o en el campo oculto MAX_FILE_SIZE de un formulario son solo una comodidad. El manual de PHP advierte que es muy fácil engañar ese ajuste desde el navegador, mientras que los límites del servidor no pueden engañarse. Configure:
- PHP:
upload_max_filesize,post_max_size(debe ser mayor) ymax_file_uploads. - Servidor web:
client_max_body_sizeen Nginx oLimitRequestBodyen Apache. - Aplicación: un límite por formulario acorde a la necesidad real (un currículum no necesita 100 MB), además de un máximo para la longitud del nombre del archivo.
- Revise
$_FILES['…']['error']y gestione los errores de tamaño con un mensaje claro.
5. Analice y maneje los archivos con seguridad
- Analice las subidas en busca de malware antes de que alguien las abra. Las opciones incluyen ClamAV en el servidor, el análisis integrado en algunos servicios de formularios o almacenamiento, o la protección de endpoints en los equipos del personal. OWASP sugiere pasar los archivos por un antivirus o un sandbox cuando sea posible.
- Las herramientas de Content Disarm & Reconstruct (CDR) reconstruyen archivos de Office y PDF sin contenido activo, algo útil en portales que reciben muchos documentos.
- Sirva las descargas de forma segura: envíe
Content-Disposition: attachmenty elContent-Typecorrecto, además deX-Content-Type-Options: nosniff, para que los navegadores no intenten mostrar un archivo disfrazado como página web. - Exija inicio de sesión para todo lo que no deba ser público y registre quién subió qué.
Lista de verificación rápida
- Lista de tipos permitidos, verificada por extensión y contenido real
- Archivos renombrados en el servidor; los nombres originales nunca se usan como rutas
- Archivos privados guardados fuera de la raíz web y servidos con control de acceso
- Ejecución de PHP bloqueada en cada carpeta pública de subidas (probado)
-
security.limit_extensions = .phpen PHP-FPM; un usuario del sistema por sitio - Límites de tamaño en PHP, en el servidor web y en la aplicación
- Análisis de malware activo; descargas enviadas con encabezados seguros
- WordPress: sin
ALLOW_UNFILTERED_UPLOADS, roles revisados
Haga revisar sus formularios de subida
Si su sitio recibe currículums, documentos de clientes o fotos, una revisión breve puede confirmar que estas protecciones están activas. Core Florida IT protege sitios web, instalaciones de WordPress y servidores web para empresas de Miami-Dade y el sur de Florida, y de forma remota en todo el país. Solicite una evaluación de TI gratuita para empezar.


