Ошибки смешанного содержимого (mixed content): причины и решение
Практика3 минРедакция Innovialabs
Коротко
Mixed content — это когда HTTPS-страница загружает скрипты, стили или картинки по обычному HTTP; найдите их в DevTools, замените адреса на HTTPS в коде и базе данных, а upgrade-insecure-requests добавьте как страховку.
Что такое смешанное содержимое
Mixed content возникает, когда страница открыта по HTTPS, а часть её ресурсов — скрипты, стили, картинки, шрифты, iframe, запросы к API — всё ещё запрашивается по http://. Сама страница зашифрована, а эти запросы нет, и злоумышленник в той же сети может их прочитать или подменить.
Браузеры реагируют по-разному:
- Активное содержимое (скрипты, стили, iframe, запросы
fetch/XHR) блокируется. Именно поэтому после перехода на HTTPS у сайта внезапно «слетают» стили или перестаёт работать виджет. - Пассивное содержимое (картинки, аудио, видео) современные браузеры обычно сами пытаются загрузить по HTTPS. Если по HTTPS ресурс недоступен, он просто не загрузится, а у замка в адресной строке может появиться предупреждение.
Решение всегда одно: каждый ресурс должен запрашиваться по HTTPS.
Откуда оно берётся после перехода на HTTPS
- Жёстко прописанные адреса в шаблонах, CSS (
background: url(http://...)) и JavaScript. - База данных CMS хранит абсолютные ссылки в записях, настройках и виджетах. WordPress, например, сохраняет
http://-адреса картинок прямо в тексте поста. - Неверный адрес сайта в конфиге — приложение строит ссылки от базового URL, который всё ещё начинается с
http://. - Reverse proxy или балансировщик снимает TLS, приложение видит обычный HTTP-запрос и генерирует
http://-ссылки. Ему нужно доверять заголовкуX-Forwarded-Proto. - Сторонние вставки — старые счётчики, виджеты и CDN, добавленные много лет назад.
Как найти небезопасные ресурсы
- Откройте страницу и DevTools → Console. Каждый заблокированный или переписанный запрос отображается как предупреждение «Mixed Content» с точным адресом.
- Проверьте вкладку Network: смотрите на схему всех запросов, включая те, что появляются после кликов и прокрутки.
- Поищите по коду:
grep -rn "http://" --include=*.{html,css,js,php,tsx,twig} .
- Поищите в дампе базы данных свой домен с
http://. - На больших сайтах обойдите все страницы краулером или соберите отчёты через Content Security Policy в режиме report-only: браузер будет сообщать о нарушениях, ничего не блокируя.
Content-Security-Policy-Report-Only: default-src https: data: blob: 'unsafe-inline' 'unsafe-eval'; report-uri /csp-report
Как исправить в коде
- Замените
http://наhttps://у всех ресурсов, которые это поддерживают. - Для своих файлов используйте пути от корня (
/assets/app.css) — они автоматически наследуют схему страницы. - Вынесите базовый URL в переменную окружения и укажите в ней
https://. - За прокси включите в фреймворке доверие к заголовкам прокси, чтобы приложение знало, что исходный запрос был по HTTPS.
- Если у стороннего ресурса нет HTTPS-версии, замените его или разместите у себя. Безопасного способа оставить его как есть не существует.
Как исправить в базе данных CMS
Не запускайте обычный SQL REPLACE по таблицам WordPress: часть значений хранится как сериализованные PHP-массивы с длиной строк, и слепая замена их ломает. Используйте инструмент, который понимает сериализацию, например WP-CLI:
wp db export backup.sql
wp search-replace 'http://example.com' 'https://example.com' --all-tables --dry-run
wp search-replace 'http://example.com' 'https://example.com' --all-tables
Сначала обязательно сделайте резервную копию и посмотрите результат пробного запуска. Затем обновите адрес сайта в настройках и очистите все кэши (страниц, CDN, объектный), иначе продолжит отдаваться старый HTML.
upgrade-insecure-requests как страховка
Директива CSP upgrade-insecure-requests заставляет браузер переписывать все http://-запросы ресурсов страницы на https:// до отправки. Добавьте её заголовком ответа:
add_header Content-Security-Policy "upgrade-insecure-requests" always;
Или meta-тегом в <head>:
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
Помните об ограничениях:
- Она не делает ресурс доступным по HTTPS. Если у сервера нет HTTPS-версии, запрос упадёт.
- Она не переписывает ссылки на другие сайты, по которым кликает пользователь.
- Она скрывает проблемы, а не устраняет их, поэтому это страховка, а не исправление.
После наведения порядка включите HSTS, чтобы браузеры всегда открывали ваш домен по HTTPS.