Недавно мы делали проект лапшеснимателя — он подсвечивал потенциальные манипуляции в тексте. Чтобы это был хотя бы минимально полезный продукт, мы должны были запускать скрипт лапшеснимателя на чужих страницах. И на одних сайтах всё запускалось без проблем, а на некоторых других скрипт не заводился.
Для нас как авторов скрипта это плохо. А для нас как веб-мастеров это интересно: можно ли защитить наши собственные сайты от взломов через скрипты?
👉 В этой статье мы разберём только один способ защиты. В жизни всё работает несколько сложнее и векторов атаки гораздо больше. Мы намеренно несколько упрощаем подачу.
Зачем нужна защита от вставки скриптов
Допустим, у нас есть сайт, который обрабатывает персональные данные пользователей: Ф. И. О. и номера телефонов. Часть этих данных получается и обрабатывается в JS-скрипте. Если немного изменить этот скрипт, можно обработать не только свои данные, но и получить данные всех пользователей сайта.
Чтобы изменить скрипт на странице или добавить в него новые команды, используют разные способы, например:
- вставлять специальные команды в консоли, как это делали мы;
- передавать вредоносный код внутри параметров адреса сайта;
- отправить специальную JSON-строку, при парсинге которой может выполниться нужный нам код.
Каждый из этих способов может добавить на страницу свой код и выполнить её как бы от имени страницы сайта. Опасность тут в том, что обычно сайт доверяет тому, что делают его собственные страницы. Если от неё придёт запрос «Отдай мне список всех фамилий и телефонов» и сервер сможет это сделать — он это сделает, и список уйдёт в чужие руки.
Решение: политика безопасности контента
Чтобы защитить сайт и страницы от таких атак, придумали CSP — политику безопасности контента. Работает это так:
- Вы специальными командами говорите сайту, из каких источников можно загружать данные для страницы.
- Эти команды отправляются браузеру при каждой загрузке страницы.
- Браузер смотрит, что написано в этих командах, и запрещает любые действия с содержимым страницы, если это не разрешено правилами.
CSP может запрещать загрузку чужих:
- скриптов,
- картинок,
- аудио- и видеофайлов,
- CSS-стилей,
- шрифтов.
Также политика безопасности может запретить обмениваться данными с любыми другими сайтами, которых нет в разрешённом списке.
Проще говоря, CSP — это фейсконтроль для любых данных, которые кто-то хочет добавить на страницу. Например, мы указали в политике, что картинки и скрипты можно загружать с нашего сайта. Когда злоумышленник попробует встроить на страницу другую картинку и свой скрипт, у него ничего не получится.
Покажите примеры
Мы хотим запретить выполнение чужих скриптов на странице. За это отвечает свойство script-srс
, у которого может быть один из этих параметров:
‘self’
— означает, что можно выполнять только те скрипты, которые лежат на том же сервере, что и страница‘none’
— вообще запрещает любые скрипты на странице, даже если они там есть- ❌
‘unsafe-inline’
— опасно, потому что этот параметр разрешает выполнение любых внешних скриптов на странице
Получается, что для блокировки всех чужих скриптов на странице нам достаточно написать в политике безопасности:
Content-Security-Policy: script-src 'self'
Если мы ещё доверяем серверам Яндекса и хотим встраивать их скрипты у себя на страницах (например, плагины Яндекс Музыки), то можем написать так:
Content-Security-Policy: script-src 'self' yandex.ru
Когда мы вообще не доверяем никому и хотим сами контролировать и поставлять весь контент на странице, то используем свойство default-src
. Оно отвечает за все источники сразу, хоть скрипты, хоть картинки. Поэтому наша политика безопасности в этом случае может выглядеть так:
Content-Security-Policy: default-src 'self'
А как это использовать?
Чтобы вся эта магия работала, нам нужно сообщить браузеру о нашей политике безопасности. Это можно сделать несколькими способами.
Настроить политику на сервере. Если так сделать, то все страницы, которые отправляются с нашего сервера, будут уже идти с нужными настройками безопасности. Самый простой способ — прописать политику в файле .htaccess, который лежит в корне сайта:
<ifModule mod_headers.c>
Header set Content-Security-Policy «default-src ‘self'»
</ifModule>
Если у вас на хостинге стоит отдельный веб-сервер Apache, то в его конфигурационный файл httpd.conf можно написать так:
Header set Content-Security-Policy "default-src 'self';"
Настроить политику на уровне движка сайта. Например, у вас есть сайт на Вордпрессе или другой CMS, которая работает на PHP. Тогда мы можем добавить в модуль, который отвечает за сборку страницы, такую строку:
header("Content-Security-Policy: default-src 'self'");
В этом случае у нас каждая страница, которую собирает движок, будет отправляться с нужными заголовками. Браузер их увидит и сделает всё, что там написано.
Вручную писать нужные параметры в метатегах внутри страницы. Это самый сложный путь — нам придётся написать теги внутри каждой страницы. Ещё один минус такого решения — теги не действуют на ресурсы, которые расположены на странице перед ним. Например, в разделе <head> мы подключим скрипты и стили, расположенные на других сайтах, а потом напишем так:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
В этом случае мы хоть и запрещаем загрузку любых ресурсов с чужих серверов, но на скрипты, написанные или подключённые до этой команды, это не влияет. Если злоумышленник сможет их подменить — защита не сработает.
И что, этого достаточно?
Нет, но это ещё один уровень защиты сайта от злоумышленников и хакеров. Вот несколько других инструментов:
- безопасное соединение, чтобы между сервером и пользователем никто не смог заменить страницу;
- проверка и отключение инжектов на стороне сервера;
- безопасные пароли и защищённые страницы входа в панель администратора;
- двухфакторная авторизация для администраторов;
- мониторинг подозрительной активности пользователей.
И есть вещи, с которыми очень сложно бороться с помощью программирования, — например, фишинг и социальная инженерия. Но всё это темы для отдельных разговоров.
Что дальше
Дальше настроим политику безопасности на нашем учебно-боевом сервере и проверим, как она работает. Заодно посмотрим, какие ещё у неё есть важные параметры и как ими управлять.