|

El .htaccess no protege tus backups (y así lo verificás)

En pocas palabras: nginx nunca lee .htaccess: es un mecanismo exclusivo de Apache, así que en un host nginx el bloque “deny all” no hace nada y la URL del dump se descarga directo. Y en Apache con AllowOverride None también se ignora. La única defensa real es sacar el dump del document root.

Corrés mysqldump > backup.sql antes de una actualización, terminás el laburo y te olvidás del archivo. Meses después, cualquiera que tipee la URL exacta se baja el dump con todos tus datos. El .htaccess que supuestamente protege esa carpeta puede no estar haciendo nada, y no lo sabés hasta que lo revisás.

Proteger backups de base de datos en hosting no depende de un solo archivo .htaccess: depende de que tu servidor lo lea, de que la carpeta no se recree sin él y de que el dump no haya nacido fuera de la carpeta protegida. En nginx ese archivo es texto muerto. La única defensa que sobrevive a todo es sacar el dump del document root.

En 30 segundos

  • nginx nunca leyó .htaccess: es un mecanismo exclusivo de Apache. En un host nginx, el bloque “deny all” es decoración y la URL del dump resuelve directo a la descarga.
  • Apache también puede ignorarlo: con AllowOverride None (la configuración que Apache recomienda en producción por performance) el .htaccess deja de aplicarse.
  • La mayoría de los dumps ni pasan por la carpeta protegida: los que salen de phpMyAdmin, del panel de hosting o de mysqldump manual caen donde vos estabas trabajando, con el nombre que vos elegiste.
  • Un dump SQL público expone todo: emails, direcciones, hashes de contraseñas, credenciales SMTP y claves API de los módulos de pago.
  • La única solución definitiva: mover los backups fuera del directorio web. Si no es accesible por URL, ninguna config de servidor lo puede servir por accidente.

¿Qué es un archivo .htaccess y por qué no siempre protege tus backups?

Un .htaccess es un archivo de configuración distribuida que Apache lee en cada directorio para aplicar reglas locales: redirecciones, reescrituras de URL y bloqueos de acceso. La clave está en “que Apache lee”. Es un mecanismo del servidor Apache, no un permiso del sistema de archivos ni una propiedad del archivo protegido. Si el servidor no lo interpreta, no pasa nada.

Acá está la trampa. Muchos CMS y tiendas online (PrestaShop es el ejemplo del reporte de dev.to publicado el 27 de agosto de 2026) instalan un .htaccess con “deny from all” dentro de la carpeta de backups. Suena razonable. El problema es que toda la protección se apoya en un archivo de texto que el servidor tiene que elegir leer.

La carpeta de backups (en PrestaShop, admin-dev/backups/) está adentro del web root. Ningún tramo de esa ruta queda fuera del document root. Traducido: el dump es servible por URL, y lo único que se interpone es ese texto. Si el texto no se lee, el archivo se descarga.

¿nginx interpreta los archivos .htaccess?

No. nginx no interpreta archivos .htaccess y nunca tuvo ese mecanismo. En un host nginx, un .htaccess es un archivo de texto sin ningún significado especial: el bloque “deny all” es inerte y la URL del dump resuelve directo al contenido. La configuración de nginx vive en los bloques server y location, no en archivos por directorio. En nuestro artículo sobre cómo configurar seguridad en tu infraestructura cloud profundizamos sobre esto.

Y ojo con esto: buena parte del hosting gestionado moderno corre nginx, o nginx adelante de Apache sirviendo los archivos estáticos de forma directa. Ese esquema híbrido produce exactamente el mismo resultado para un .htaccess (nginx atiende el .sql antes de que Apache lo vea).

Apache tampoco es garantía. Desde Apache 2.4, la propia documentación recomienda AllowOverride None en producción por razones de performance (leer un .htaccess en cada request tiene costo). Con esa opción, el archivo existe pero Apache lo saltea entero. Si nunca chequeaste qué servidor tenés, no sabés si ese archivo hace algo.

Escenario del servidor¿Lee el .htaccess?¿El dump queda protegido?
Apache con AllowOverride AllSí (mientras el archivo esté presente)
Apache con AllowOverride None (recomendado en prod)NoNo, se descarga
nginx puroNo (no existe el mecanismo)No, se descarga
nginx frente a Apache (estáticos por nginx)No para el .sqlNo, se descarga
proteger backups base de datos hosting diagrama explicativo

Las 4 formas en que la protección desaparece aunque tengas .htaccess

Aunque el .htaccess esté ahí y bien escrito, hay cuatro maneras concretas de que deje de proteger tus backups. Las cuatro son situaciones de trabajo normal, no negligencia dramática.

1. Tu servidor no lee el archivo

Ya lo vimos: nginx no lo lee jamás, y Apache con AllowOverride None tampoco. En cualquiera de esos dos casos, el bloque “deny all” nunca se ejecuta. El dump está expuesto desde el minuto cero, sin que nadie haya tocado nada.

2. La carpeta vuelve sin el archivo

El código que escribe el dump no escribe el .htaccess. Ese archivo existe solo porque vino con la instalación. Borrás la carpeta de backups para liberar espacio y dejás que algo la recree, deployás con una lista de archivos hecha a mano que omite los dotfiles, restaurás desde un archivo armado con un glob que se saltó los archivos ocultos… y la carpeta vuelve con dumps adentro y nada que la cuide. Pasa tanto que el propio módulo de limpieza del autor del reporte reescribe el par de archivos si faltan. Tema relacionado: solucionar problemas comunes de acceso al hosting.

3. El .htaccess raíz no cubre la carpeta

Tentador suponer que el .htaccess generado en la raíz (el que reescribe la página de SEO) tiene una regla para esto. No la tiene. En PrestaShop 8.2, el único bloque que genera protege una ruta puntual, sin regla para la carpeta de backups ni para las extensiones .sql. Regenerar ese .htaccess raíz (algo que se hace bastante seguido) no agrega nada acá, y si vos habías metido una regla a mano, la borra.

4. La mayoría de los dumps nunca pasó por ahí

Este es el gordo. Un dump que sale del “guardar en servidor” de phpMyAdmin, del botón de exportar del panel de hosting, o de un mysqldump > backup.sql tirado en el directorio donde se abrió la sesión SSH… ninguno cae en la carpeta protegida. Ninguno recibe nombre aleatorio. Recibe el nombre que vos elegiste, en el directorio donde estabas laburando, que muchas veces es el web root. Ninguna corrección en el .htaccess toca este caso.

¿Qué información expones si tu backup SQL es público?

Un dump de base de datos expuesto entrega, de una, todos los datos de tu operación. “Una base de datos” suena abstracto; el contenido no lo es. En una tienda PrestaShop, según el reporte, un dump incluye:

  • Datos de clientes: nombres, emails, direcciones postales, teléfonos y hashes de contraseñas de cada cuenta que la tienda tuvo alguna vez.
  • Pedidos y transacciones: qué compró cada uno y las referencias de las transacciones.
  • Cuentas del back-office: los empleados con acceso al panel y sus hashes de contraseña.
  • Configuración completa: donde el CMS y cada módulo guardan sus ajustes, incluidas las credenciales SMTP con las que la tienda manda mails, claves de webservice y las API keys de los módulos de pago y envío.

Esa última parte es la que convierte “borré el archivo” en apenas el primer paso. Si un dump fue alcanzable, las credenciales que tenía adentro hay que tratarlas como divulgadas. O sea: rotarlas, no solo borrar el archivo. Un atacante que se bajó el dump ya tiene esas claves aunque vos borres el .sql diez minutos después.

¿Cómo verifico si mis backups están accesibles en 2 minutos?

Para saber si tus backups están accesibles, buscá los archivos .sql en tu sitio y después pedí uno por HTTP desde afuera, sin estar logueado. Si el navegador te lo baja, está expuesto. Todo esto corre en tu propio servidor, así que no hay nada raro ni ilegal: le estás preguntando a tu server qué contesta. Sobre eso hablamos en proteger recursos en servidores dedicados.

Paso 1. Encontralos. Desde la raíz del sitio, corré:

find . -maxdepth 3 \( -name '*.sql' -o -name '*.sql.gz' -o -name '*.sql.zip' \)

Sumá tus extensiones de archivo comprimido. Un .tar.gz de una migración full-site es el mismo problema con otra ropa.

Paso 2. Pedíselo a tu propio servidor. Tomá la URL exacta de un archivo que acabás de encontrar y pedila desde afuera, con un navegador que no esté logueado. Es el único test que responde la pregunta de verdad, porque contesta la configuración real del servidor, no tu suposición sobre ella. Un 200 con descarga es el hallazgo.

Paso 3. Averiguá qué servidor tenés. Mirá el header Server de la respuesta o preguntale a tu hosting. Si la respuesta es nginx, cada .htaccess de ese host es decoración.

¿Dónde guardar backups de forma segura en hosting compartido?

La forma segura de guardar backups en hosting compartido es sacarlos del document root: una carpeta un nivel arriba del web root, un object storage, o tu propia máquina. Si el archivo no es direccionable por URL, ninguna configuración de servidor lo puede servir por accidente. Esa es toda la solución, y es la única que sobrevive a una migración de servidor, a un cambio de panel de control o a un colega que no conoce la regla.

Es la diferencia entre depender de una defensa activa (que algo lea y aplique una regla) y una pasiva (el archivo directamente no está donde la web puede alcanzarlo). Si armás tu infraestructura en un hosting como el de donweb.com, verificá con soporte si podés escribir en un directorio por encima de public_html; ahí es donde deberían vivir los dumps que necesitás conservar.

Todo lo demás es mitigación, en orden descendente de confiabilidad:

  • Reglas en el vhost, no en un .htaccess: un bloque “deny” o un match de extensiones .sql puesto directo en el vhost de Apache no se puede desactivar en silencio con AllowOverride None y no desaparece cuando se recrea una carpeta.
  • Borrá el dump cuando termines: casi todo dump expuesto se necesitó una sola tarde hace dos años. Un backup que guardás a propósito va a tu sistema de backups, no a una carpeta dentro de la tienda.
  • Rotá lo que hubiera adentro si el archivo fue alcanzable alguna vez: contraseñas de empleados, webservice keys, API de módulos, SMTP.

¿Qué hago si descubrí que mi backup fue público?

Si encontraste un backup expuesto, sacá el archivo y rotá todas las credenciales que contenía, en ese orden. Borrar el archivo no cierra el incidente: si estuvo abierto, hay que asumir que alguien se lo bajó.

  • Remové el archivo ya: sacá el dump del document root o borralo. Primer paso, no el último.
  • Rotá todo lo que estaba adentro: contraseñas de empleados del back-office, webservice keys, API keys de los módulos de pago y envío, credenciales SMTP. Tratalas como divulgadas.
  • Revisá los logs de acceso: buscá requests a la URL del dump para estimar si lo descargaron y desde dónde.
  • Chequeá los buscadores: Google y Bing indexan lo que pueden alcanzar. Un dump que estuvo abierto un tiempo puede ser encontrable de forma independiente de tu servidor. Buscá el nombre del archivo en Google, pedí la desindexación con las herramientas de cada buscador y confirmá que no quedó en caché. Remover el archivo es el paso uno de dos.

Errores comunes al proteger backups en hosting

Estos son los que se ven una y otra vez, con la corrección al lado.

  • Confiar en que “el CMS protege la carpeta de backups”: es verdad y no ayuda. El CMS pone un .htaccess, pero solo funciona en Apache que lo lea. Corregí verificando qué servidor tenés antes de asumir que estás cubierto.
  • Dejar el dump con el nombre que elegiste en el web root: backup.sql en la raíz es adivinable al instante. Si tenés que hacer un dump manual, generalo fuera del document root desde el arranque.
  • Guardar backups “por las dudas” indefinidamente: cada dump que conservás es una superficie de exposición más. Borralo cuando termines, o mandalo a un sistema de backups real, que no es una carpeta dentro del sitio.
  • Poner nombres predecibles con prefijo y fecha: un nombre tipo limpieza-20260827-084500.sql.gz no aporta nada al secreto. Si el nombre es predecible, toda la protección recae en el deny de carpeta, que en nginx no existe.

Preguntas Frecuentes

¿Realmente protege el .htaccess mis backups?

Solo si tu servidor es Apache y está configurado para leer archivos .htaccess (AllowOverride habilitado). En nginx no protege nada porque nginx no interpreta ese archivo. Y aun en Apache, deja de servir si borrás la carpeta y se recrea sin el archivo, o si el dump se generó fuera de la carpeta protegida.

¿nginx interpreta archivos .htaccess?

No. nginx nunca tuvo soporte para .htaccess; es un mecanismo exclusivo de Apache. En un host nginx, ese archivo es texto sin significado especial y la URL de tu backup resuelve directo a la descarga. La configuración de acceso en nginx se hace en los bloques location del server, no en archivos por directorio.

¿Cómo verifico si mis backups están accesibles públicamente?

Buscá los archivos con find . -maxdepth 3 -name '*.sql' (sumá .sql.gz y .sql.zip) y después pedí la URL exacta de uno desde un navegador sin loguear. Si te lo descarga con un 200, está expuesto. Es el único test confiable porque responde la configuración real del servidor.

¿Qué información expongo si mi backup SQL es público?

Todo lo que hay en la base: nombres, emails, direcciones y teléfonos de clientes, hashes de contraseñas, pedidos y transacciones, cuentas del panel de administración y la configuración completa, incluidas credenciales SMTP y claves API de los módulos de pago. Por eso, si un dump fue alcanzable, hay que rotar todas esas credenciales.

¿Dónde guardar backups de forma segura en hosting compartido?

Fuera del document root: un directorio un nivel arriba de public_html, un object storage externo o tu propia máquina. Si el archivo no es direccionable por URL, ninguna configuración de servidor puede servirlo por accidente. Es la única solución que sobrevive a migraciones y cambios de panel.

Conclusión

Lo que cambia acá no es una vulnerabilidad nueva: es entender que el .htaccess es una defensa condicional que la mitad del hosting moderno ni ejecuta. Si tu servidor es nginx (o Apache con AllowOverride None), ese “deny all” no hace nada, y encima la mayoría de los dumps ni siquiera nacen en la carpeta protegida.

La acción es simple y no depende de qué servidor tengas. Corré el find, pedí un dump por HTTP desde afuera y comprobá qué contesta tu server. Si algo se descarga, sacá el archivo, rotá las credenciales que tenía adentro y mové todos tus backups fuera del web root. Un backup que necesitás guardar va a un sistema de backups, no a una carpeta dentro de tu sitio. Es media hora de trabajo contra el escenario de tener la base entera de tus clientes bajable por cualquiera que tipee la URL.

Fuentes

Te puede interesar...