Si desplegaste una SPA en React (o Vue, o Angular) sobre Apache, casi con seguridad copiaste y pegaste un .htaccess como este. Funciona: arregla el routing y tus rutas profundas dejan de dar 404.
Pero tiene un problema de seguridad que la mayoría de tutoriales no menciona: ese mismo .htaccess le responde «200 OK» a todos los ataques que recibe tu sitio.

En nuestros servidores medimos el impacto real. Te contamos qué encontramos y cómo se corrige en tres líneas.
Contenido:
El .htaccess para SPA que todos usamos
Una SPA maneja el routing en el navegador. El servidor solo conoce index.html, así que si alguien entra directo a tusitio.com/nosotros, Apache busca un archivo llamado nosotros, no lo encuentra y devuelve 404.
La solución estándar es reescribir todo hacia index.html:
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
# No reescribir archivos o carpetas que existen
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Todo lo demás -> index.html
RewriteRule ^ index.html [L]
</IfModule>Funciona perfecto. Y ahí está el problema: funciona demasiado bien.
El problema: tu SPA responde «200 OK» a los ataques
Lee otra vez la última línea: «todo lo demás → index.html». Todo. Sin excepciones.
Eso significa que cuando un bot pide esto:
GET /wp-content/plugins/hellopress/wp_filemanager.php
…tu servidor no responde «404, aquí no hay nada». Responde:
HTTP/1.1 200 OK
Content-Length: 8169
Un 200 OK con tu index.html completo. Para el atacante, ese 200 significa una sola cosa: «aquí hay algo».
Por qué esto sí importa (tres razones)
1. Le confirmas al escáner que existes. Los bots priorizan objetivos por respuesta: un 404 los descarta, un 200 los invita a seguir. Estás premiando a quien te ataca.
2. Gastas recursos en cada petición basura. Un 404 cuesta casi nada. Servir tu index.html cuesta entre 3 KB y 16 KB de CPU, disco y ancho de banda — por cada intento, multiplicado por miles.
3. Ensucias tus métricas. Tus logs y analíticas se llenan de «visitas» que en realidad son bots buscando puertas traseras.
Los números reales de nuestro servidor
Esto no es teoría. En un servidor con 135 cuentas de hosting medimos, en una sola hora pico:
| Dato | Valor |
|---|---|
| Peticiones totales | 31.028 |
| Provenientes de bots en la nube (Azure/GCP) | más del 50% |
| Peticiones de una sola IP | 8.257 (≈2,3 por segundo) |
| Carga del servidor | 5,57 sobre 4 núcleos (~140%) |
¿Qué buscaban? Puertas traseras conocidas de WordPress: wp_filemanager.php, this_is_a_new_hello_world.php, wp-config.php. Y lo más revelador: no se declaraban como bots — usaban User-Agents falsos de Chrome para parecer visitantes reales.
Las SPAs les respondían 200 OK a todas. No porque estuvieran comprometidas —los archivos no existían— sino porque el .htaccess servía index.html a cualquier cosa.
La solución: tres líneas
Una SPA estática no tiene ni un solo archivo PHP. Entonces cualquier petición a un .php es, por definición, basura o ataque. Díselo a Apache:
<IfModule mod_rewrite.c>
RewriteEngine On
# 👇 LAS 3 LÍNEAS NUEVAS
# Sitio estático (sin PHP): 404 duro a rutas de ataque, en vez de servir el SPA
RewriteRule \.(php|phtml|asp|aspx|cgi|jsp)$ - [R=404,L]
RewriteRule ^wp-(admin|content|includes|login|json) - [R=404,L]
# 👆
RewriteBase /
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^ index.html [L]
</IfModule>El orden importa: las reglas nuevas van antes del fallback, para que corten la petición antes de que llegue el index.html.
¿Rompe mi aplicación?
No, y por una razón simple: tu SPA no tiene PHP. Las rutas reales de React (/nosotros, /productos/123) no terminan en .php ni empiezan con wp-. Verifícalo tú mismo antes de aplicar:
find ./dist -name "*.php" | wc -l # debe dar 0
Si da 0, es seguro. Si tu sitio sí tiene PHP (WordPress, Laravel), no apliques la regla del .php — no es tu caso.
Cómo verificar que funciona
Después de subir el .htaccess, comprueba las tres cosas:
# 1) La home sigue viva
curl -o /dev/null -w "%{http_code}\n" https://tusitio.com/
# 2) Una ruta profunda de la SPA sigue funcionando
curl -o /dev/null -w "%{http_code}\n" https://tusitio.com/nosotros
# 3) Una URL de ataque ahora debe dar 404
curl -o /dev/null -w "%{http_code}\n" https://tusitio.com/wp-content/plugins/x/shell.php
Debes obtener 200 · 200 · 404. Si el tercero sigue en 200, la regla quedó después del fallback: súbela.
Conclusión
El .htaccess para SPA en React que circula en todos los tutoriales resuelve el routing, pero deja a tu sitio respondiéndole «200 OK» a cada bot que lo escanea. Tres líneas lo convierten en un 404 barato: menos carga, menos ruido y menos razones para que un atacante insista.
Es un cambio de dos minutos. Y como todo en seguridad, lo que menos cuesta es lo que se hace antes de necesitarlo.
En Marbust Websites® aplicamos este tipo de endurecimiento en cada proyecto que entregamos, y en MBHostCloud® lo monitoreamos a nivel de servidor. ¿Tu sitio responde 200 a los ataques? Escríbenos a Sites@MarBust.com y lo revisamos contigo.
Te invitamos a seguir explorando nuestro blog para más contenido sobre tecnología, emprendimiento y soluciones digitales.
Síguenos en nuestras redes sociales y visita nuestra sala de prensa para más noticias, guías y consejos tecnológicos. 🚀
Facebook, X (Twitter), YouTube, LinkedIn, Instagram
Sobre el Autor

Marco Antonio Bustillos Quiroz
Bachelor of Science in Web Design and Development (BYU–Idaho)
Full Stack Web Developer con más de 8 años de experiencia en desarrollo Front End y Back End. Mis proyectos incluyen sitios web, landing pages, aplicaciones web, REST APIs, e-commerce, y mucho más. Mi pasión es crear experiencias digitales impactantes y compartir conocimientos con otros desarrolladores y entusiastas de la tecnología.