El contenido mixto ocurre cuando una página HTTPS carga sub-recursos (imágenes, scripts, hojas de estilo, fuentes) a través de HTTP plano. Los navegadores bloquean o advierten sobre esto porque un recurso inseguro en una página segura socava la seguridad de toda la página.
Dos tipos de contenido mixto
| Tipo | Ejemplos | Comportamiento del navegador |
|---|---|---|
| Activo (peligroso) | Scripts, iframes, XHR, CSS | Bloqueado por todos los navegadores |
| Pasivo (display) | Imágenes, audio, video | Se muestra con advertencia / candado degradado |
El contenido mixto activo puede modificar la página (un intermediario podría inyectar JavaScript malicioso), por lo que los navegadores lo bloquean completamente. El contenido mixto pasivo es menos peligroso pero aún degrada el indicador de seguridad.
Cómo encontrar contenido mixto
DevTools del navegador
- Abre tu sitio en Chrome/Firefox
- Abre DevTools (F12) → pestaña Console
- Busca errores como:
Mixed Content: The page at 'https://example.com' was loaded over HTTPS, but requested an insecure resource 'http://example.com/image.jpg'.
Escaneo por línea de comandos
curl -s https://yourdomain.com | grep -oP 'http://[^"'"'"'> ]+' | sort -u
Causas comunes y soluciones
URLs http:// codificadas en el HTML
<!-- Problem -->
<img src="http://example.com/logo.png">
<!-- Fix: use protocol-relative or HTTPS -->
<img src="https://example.com/logo.png">
<img src="//example.com/logo.png">
<img src="/logo.png">
Práctica recomendada: usa rutas relativas (/images/logo.png) siempre que sea posible.
Recursos de terceros aún en HTTP
<!-- Problem -->
<script src="http://cdn.example.com/library.js"></script>
<!-- Fix -->
<script src="https://cdn.example.com/library.js"></script>
Si el tercero no soporta HTTPS, busca un proveedor alternativo o aloja el recurso tú mismo.
Contenido de base de datos con URLs codificadas
WordPress y otros CMS almacenan URLs absolutas en la base de datos. Después de migrar a HTTPS:
-- WordPress: update URLs in posts
UPDATE wp_posts SET post_content = REPLACE(post_content, 'http://example.com', 'https://example.com');
UPDATE wp_options SET option_value = REPLACE(option_value, 'http://example.com', 'https://example.com');
O usa un plugin como Better Search Replace.
CSS con referencias HTTP
/* Problem */
background-image: url('http://example.com/bg.jpg');
/* Fix */
background-image: url('https://example.com/bg.jpg');
background-image: url('/images/bg.jpg');
Content Security Policy (CSP) — prevenir contenido mixto futuro
Añade una cabecera CSP que bloquee recursos HTTP:
Nginx:
add_header Content-Security-Policy "upgrade-insecure-requests" always;
Apache:
Header always set Content-Security-Policy "upgrade-insecure-requests"
upgrade-insecure-requests indica a los navegadores que actualicen automáticamente las solicitudes http:// a https://, una red de seguridad mientras corriges las URLs en el código fuente.
Corrección sistemática: auditoría completa del sitio
Para una limpieza exhaustiva, audita todo tu sitio:
1. Rastrear referencias HTTP
# Scan all HTML files for http:// URLs
find /var/www/html -name '*.html' -o -name '*.php' | xargs grep -l 'http://' 2>/dev/null
# Scan CSS files
find /var/www/html -name '*.css' | xargs grep -l 'http://' 2>/dev/null
# Scan JavaScript files
find /var/www/html -name '*.js' | xargs grep -l 'http://' 2>/dev/null
2. Corregir URLs por categoría
| Fuente | Método de corrección |
|---|---|
| Tus propios recursos | Cambiar a rutas relativas (/images/logo.png) |
| Recursos de CDN | Actualizar a https://cdn.example.com/... |
| Scripts de terceros | Actualizar URL o encontrar alternativa HTTPS |
| CSS en línea | Buscar-reemplazar http:// → https:// |
| Contenido de base de datos (WordPress) | wp search-replace 'http://yourdomain.com' 'https://yourdomain.com' |
| Archivos de plantilla/tema | Editar archivos fuente directamente |
3. Verificar con DevTools del navegador
Después de corregir, abre cada página → DevTools (F12) → pestaña Console. Una página limpia no muestra advertencias de contenido mixto. El icono de candado debe ser sólido (sin romper ni con triángulo de advertencia).
4. Prevenir contenido mixto futuro
Añade esta meta etiqueta al <head> de tu HTML como red de seguridad permanente:
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
O configúralo a nivel del servidor vía la configuración de Nginx/Apache (mostrado arriba).
Tipos de contenido que comúnmente causan contenido mixto
| Tipo de contenido | Dónde verificar | Ejemplo |
|---|---|---|
| Imágenes | <img src="http://..."> | Imágenes subidas, avatares, logos |
| Scripts | <script src="http://..."> | Analíticas, widgets de chat, scripts publicitarios |
| Hojas de estilo | <link href="http://..."> | Fuentes externas, frameworks CSS |
| Fuentes | @font-face { src: url("http://...") } | Google Fonts (generalmente bien), fuentes personalizadas |
| Iframes | <iframe src="http://..."> | Videos embebidos, mapas, widgets |
| XHR/Fetch | fetch("http://...") | Llamadas a API en JavaScript |
| Imágenes de fondo | background-image: url("http://...") | Fondos CSS |
Preguntas frecuentes
¿El contenido mixto afecta mi SEO?
No directamente. Google rastrea basándose en el protocolo de la URL de la página, no en los sub-recursos. Sin embargo, si el contenido mixto provoca advertencias del navegador o bloquea contenido visible, la experiencia de usuario se degrada, lo que puede afectar indirectamente el posicionamiento a través de tasas de rebote más altas.
¿Puedo simplemente usar upgrade-insecure-requests y no corregir las URLs?
Funciona como solución temporal, pero corregir las URLs en el código fuente es mejor. La cabecera CSP depende del soporte del navegador (todos los navegadores modernos lo soportan, pero algunos clientes antiguos no) y añade una cabecera adicional a cada respuesta.
Mi sitio tiene cientos de URLs HTTP codificadas. ¿Cuál es la corrección más rápida?
Añade la cabecera CSP upgrade-insecure-requests inmediatamente (una línea de configuración del servidor). Luego haz un buscar-reemplazar global en tu código fuente y base de datos. Usa grep -r 'http://' src/ para encontrar URLs codificadas en el código.