Security.txt — как настроить понятный канал для сообщений об уязвимостях

Security.txt — как настроить понятный канал для сообщений об уязвимостях

Простой способ направить исследователей в правильную сторону.

image

Идея похожа на robots.txt, только для безопасности. Смысл не в «бумажке ради бумаги», а в снижении трения между исследователем и компанией. Вы даёте понятную точку входа, а взамен получаете сообщения по делу, меньше хаоса и шанс исправить проблему до того, как о ней узнают посторонние.

Что такое security.txt и где он живёт

security.txt — обычный текстовый файл в кодировке UTF-8. Его основное место — https://ваш-домен/.well-known/security.txt. Для совместимости допускается копия в корне сайта по адресу /security.txt, но приоритет у варианта в каталоге /.well-known/. Файл должен отдаваться по HTTPS с типом содержимого text/plain; charset=utf-8. Это важно для автоматических сканеров и просто хорошего тона.

Файл относится именно к тому домену, с которого его скачали. Если у вас есть несколько поддоменов или витрин, для каждого лучше публиковать свой экземпляр. Так вы избежите двусмысленности: кто отвечает за конкретную площадку и куда писать.

Какие задачи решает security.txt

Во-первых, он экономит время. Исследователь не ищет случайные адреса в подвалах страниц и не спорит с техподдержкой, а сразу попадает на правильный канал. Во-вторых, вы задаёте рамки взаимодействия: что можно тестировать, как оформлять отчёт, как быстро ждать ответа. В-третьих, это укрепляет репутацию — видно, что компания относится к сообщениям об уязвимостях серьёзно и не игнорирует обратную связь.

Отдельный плюс для команд безопасности — дисциплина внутри. Как только появляется понятный вход, появляется и понятная очередь: письма автоматически попадают в трекер, статус двигается, сроки контролируются. Никакой магии, просто порядок.

Структура файла: поля и комментарии

Файл состоит из строк вида «поле: значение». Комментарии начинаются с символа # и игнорируются. Некоторые поля можно повторять несколько раз, сохраняя порядок предпочтения. Пустые строки допустимы для читаемости. Не используйте HTML или JSON — это именно простой текст.

Ниже перечислены поля, которые встречаются чаще всего. Два из них обязательны: Contact и Expires. Остальные добавляют удобства и повышают доверие, но формально не требуются.

Обязательные поля

Contact — канал связи для отчётов. Можно указать несколько значений: mailto:, страницу с формой обратной связи, сервисный портал, иногда номер телефона для экстренных случаев. Размещайте в порядке предпочтения. Если используете электронную почту, лучше сразу предложить шифрование (см. поле Encryption).

Expires — срок актуальности файла. После указанной даты информацию нельзя считать свежей. Формат — дата и время по международному стандарту (например, 2026-03-31T12:00:00Z). Рекомендуемый горизонт — не больше года. Продлевать можно заранее, это вполне нормальная практика.

Часто используемые дополнительные поля

Policy — ссылка на политику ответственного раскрытия уязвимостей. Здесь уместно описать границы тестирования, пример отчёта, сроки обратной связи, как вы поступаете с демонстрационными эксплойтами и что делать в случае утечки данных.

Encryption — ссылка на открытый ключ для шифрования переписки. Обычно размещают OpenPGP-ключ, опубликованный на вашей странице или в репозитории. Сам ключ в поле не вставляют — только ссылку или отпечаток.

Acknowledgments — страница благодарностей исследователям. Это мотивирует сообщать ответственно и помогает выстроить доверие. По желанию можно публиковать «зал славы» с именами, датами и краткими описаниями найденных проблем.

Preferred-Languages — список языков, на которых вам удобнее получать сообщения. Пример: ru, en. Если поле не указано, по умолчанию обычно предполагают английский.

Hiring — ссылка на вакансии в области безопасности. Поле не влияет на обработку отчётов, но помогает тем, кто хочет к вам присоединиться.

Canonical — канонический URI самого файла. Полезно, если размещаете одинаковые копии на нескольких хостах и хотите зафиксировать «главный» адрес.

Готовые примеры

Минимальный рабочий вариант

# Контакт службы безопасности
Contact: mailto:security@example.com

# Срок действия информации
Expires: 2025-12-31T23:59:59Z

Расширенный вариант с политикой, ключом и языками

# Канонический адрес файла
Canonical: https://example.com/.well-known/security.txt

# Каналы связи по убыванию предпочтения
Contact: https://example.com/security
Contact: mailto:security@example.com

# Ссылка на открытый ключ для шифрования
Encryption: https://example.com/keys/security-pgp.txt

# Политика ответственного раскрытия
Policy: https://example.com/vulnerability-disclosure

# Благодарности исследователям
Acknowledgments: https://example.com/hall-of-fame

# Предпочтительные языки общения
Preferred-Languages: ru, en

# Срок актуальности файла
Expires: 2026-03-31T12:00:00Z

Подписанный файл (clearsign OpenPGP)

Можно публиковать файл в «прозрачно подписанном» виде. Внутри виден текст и криптографическая подпись. Это повышает доверие и защищает от скрытой подмены, если кто-то попытается отдать ложный файл через прокси.

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256

Contact: mailto:security@example.com
Encryption: https://example.com/keys/security-pgp.txt
Policy: https://example.com/vulnerability-disclosure
Acknowledgments: https://example.com/hall-of-fame
Preferred-Languages: ru, en
Expires: 2026-03-31T12:00:00Z
-----BEGIN PGP SIGNATURE-----
...подпись...
-----END PGP SIGNATURE-----

Размещение на сервере: краткие рецепты

Главные требования — доступность по /.well-known/security.txt, HTTPS и корректный тип содержимого. Ниже — короткие примеры для популярных веб-серверов. Настройки нужно адаптировать под вашу инфраструктуру.

Nginx

server {
  listen 443 ssl;
  server_name example.com;

  # ...ваши настройки TLS и корня сайта...

  location = /.well-known/security.txt {
    default_type text/plain; charset=utf-8;
    add_header X-Content-Type-Options nosniff;
    try_files $uri =404;
  }
}

Apache HTTP Server

# Включите mod_alias (обычно включен)
Alias "/.well-known/security.txt" "/var/www/security/security.txt"
<Files "/var/www/security/security.txt">
  ForceType text/plain; charset=utf-8
  Header set X-Content-Type-Options "nosniff"
</Files>

IIS

<configuration>
  <system.webServer>
    <staticContent>
      <mimeMap fileExtension=".txt" mimeType="text/plain; charset=utf-8" />
    </staticContent>
    <rewrite>
      <rules>
        <rule name="SecurityTxt">
          <match url="^\.well-known/security\.txt$" />
          <action type="Rewrite" url="D:\site\security\security.txt" />
        </rule>
      </rules>
    </rewrite>
  </system.webServer>
</configuration>

Как проверить, что всё работает

Проверка нужна по двум причинам. Сначала убедиться, что файл вообще доступен и отдаётся корректно. Затем — что в нём нет опечаток, просроченной даты и нерабочих ссылок. Начните с простого запроса командой curl и посмотрите заголовки.

$ curl -i https://example.com/.well-known/security.txt
HTTP/2 200
content-type: text/plain; charset=utf-8
content-length: 342
x-content-type-options: nosniff

Contact: mailto:security@example.com
Policy: https://example.com/vulnerability-disclosure
Preferred-Languages: ru, en
Expires: 2026-03-31T12:00:00Z

Дальше проверьте, что дата в поле Expires ещё не истекла. Перейдите по ссылке из Policy и убедитесь, что страница доступна. Если публикуете ключ шифрования, скачайте его и проверьте отпечаток. В качестве дополнительных тестов пригодятся онлайн-проверки:

Как встроить в процессы

Файл сам по себе проблему не решает. Важно, что будет происходить дальше. Организуйте базовый поток обработки: письма с адреса из Contact автоматически попадают в систему отслеживания задач, назначаются ответственным, по ним выставляются сроки. Если у вас нет отдельной команды, назначьте дежурных из разработки и эксплуатации, чтобы никто не перекладывал сообщение «на потом».

В политике раскройте ожидаемый формат отчёта. Например: краткое описание, влияние, шаги воспроизведения, артефакты (скриншоты, proof of concept), возможные обходные варианты. Это уменьшит переписку и ускорит разбор. Сроки ответа тоже обозначьте честно — лучше пообещать немного и выполнить, чем наоборот.

Если команде не хватает базовой практики по этичному тестированию и корректной коммуникации с исследователями, закройте этот пробел обучением. В качестве стартовой ступени подойдёт практический курс «Белый хакер» — он помогает выстроить аккуратный подход к поиску уязвимостей и ответственному раскрытию.

Автоматизация: чтобы Expires не подводил

Чаще всего забывают продлить срок в Expires. Это легко автоматизировать. Простейший путь — хранить файл в репозитории, а при каждом релизе шаблон обновлять скриптом. Ниже — наглядная заготовка на оболочке.

#!/usr/bin/env bash
# Генерация security.txt с продлением на 270 дней и подписью OpenPGP

DOMAIN="example.com"
OUT="/var/www/security/security.txt"
KEY_URL="https://$DOMAIN/keys/security-pgp.txt"
POLICY_URL="https://$DOMAIN/vulnerability-disclosure"
HOF_URL="https://$DOMAIN/hall-of-fame"
LANGS="ru, en"
EXPIRES="$(date -u -d '+270 days' +'%Y-%m-%dT%H:%M:%SZ')"

cat > "$OUT" <<TXT
Canonical: https://$DOMAIN/.well-known/security.txt
Contact: https://$DOMAIN/security
Contact: mailto:security@$DOMAIN
Encryption: $KEY_URL
Policy: $POLICY_URL
Acknowledgments: $HOF_URL
Preferred-Languages: $LANGS
Expires: $EXPIRES
TXT

# Необязательно: прозрачная подпись, если настроен gpg
# gpg --clearsign --local-user security@$DOMAIN --output "$OUT" "$OUT"

Добавьте проверку в пайплайн: после деплоя скрипт делает curl и проверяет код ответа, тип содержимого и свежесть даты. Если что-то не так, сборка падает и вы видите проблему до релиза.

Типичные ошибки и как их избежать

Нет поля Expires. Без него файл считается неактуальным. Даже если всё остальное заполнено правильно, автоматическая проверка может проигнорировать такой файл.

Просроченная дата. Классика. Помогает автоматическое продление и напоминание в календаре команды. Не ставьте горизонт больше года — лучше обновлять чуть чаще.

Ссылки без HTTPS. Поля со ссылками должны указывать на защищённые адреса. Любое исключение подрывает доверие к документу.

Вставили открытый ключ прямо в поле Encryption. В поле должна быть ссылка, а сам ключ — по этой ссылке. Так проще менять ключ и проверять его отпечаток.

Отдаёте HTML вместо текста. Проследите за типом содержимого. Должно быть text/plain; charset=utf-8. Некоторые серверы по умолчанию пытаются «угадать» тип и подменяют его.

Недоступный контакт. Адрес вида noreply@ или форма без уведомлений — путь в никуда. Письма должны попадать в рабочую очередь, а не в почтовый мешок.

Одна копия на все субдомены. Лучше публиковать отдельные файлы. Так вы явно показываете, кто отвечает за конкретный сервис, и избегаете коллизий.

Варианты для разных организаций

Небольшой проект. Достаточно одного адреса mailto:, аккуратной политики на одной странице и свежего Expires. Не усложняйте раньше времени. Главное — чтобы письма быстро доходили до тех, кто может исправить проблему.

Средняя компания. Добавьте форму на сайте, настройте интеграцию с системой задач и укажите предпочитаемые языки. Публикуйте ключ шифрования и продумайте шаблон ответа: «получили, разбираем, ориентировочный срок — такой-то». Страницу благодарностей можно сделать простым списком.

Группа компаний и холдинги. Чаще всего удобна отдельная зона вида security.company.tld с единой политикой и контактами CSIRT. На каждую публичную витрину — свой security.txt со ссылкой на общую политику и локальные нюансы. Для каналов связи используйте очередь с приоритизацией и отчётами.

Шаблоны, которые можно взять за основу

Стартовый policy-скелет (на одной странице)

<h1>Ответственное раскрытие уязвимостей</h1>
<p>Мы благодарны исследователям, помогающим делать наши сервисы безопаснее. Ниже — как прислать отчёт и что ожидать в ответ.</p>

<h2>Что мы принимаем</h2>
<ul>
  <li>Уязвимости, влияющие на конфиденциальность, целостность или доступность данных.</li>
  <li>Ошибки аутентификации и авторизации, инъекции, XSS, RCE и другие существенные проблемы.</li>
</ul>

<h2>Границы тестирования</h2>
<p>Запрещены атаки, приводящие к отказу в обслуживании, массовой рассылке, социальной инженерии сотрудников и пользователeй, а также доступ к данным третьих лиц.</p>

<h2>Как оформить отчёт</h2>
<ol>
  <li>Краткое описание и влияние.</li>
  <li>Шаги воспроизведения.</li>
  <li>Ожидаемое и фактическое поведение.</li>
  <li>Артефакты: скриншоты, логи, PoC.</li>
</ol>

<h2>Наши сроки</h2>
<p>Подтверждаем получение отчёта в течение 3 рабочих дней, делимся предварительной оценкой в течение 10 рабочих дней. По согласованию координируем раскрытие информации.</p>

<h2>Шифрование</h2>
<p>Если отчёт содержит чувствительные данные, используйте наш открытый ключ по ссылке в файле security.txt.</p>

Особые случаи: мобильные приложения, CDN и офлайн-сервисы

Мобильные приложения. Для магазинов приложений удобнее дать ссылку на страницу политики на вашем сайте, а в самом приложении — раздел «Поддержка и безопасность». Если есть домен, публикуйте security.txt именно там.

CDN и прокси. Убедитесь, что кэш не мешает обновлению файла, особенно при продлении Expires. Для /.well-known/ обычно хватает умеренного кэша или полного запрета кэширования.

Сервисы без сайта. Если у вас есть API на отдельном домене, размещайте файл именно там. Для чистого IP-адреса без домена файл не пригодится — лучше выделить доменное имя.

Чеклист перед публикацией

  • Файл доступен по адресу /.well-known/security.txt и отдаётся как text/plain; charset=utf-8.
  • Заполнены Contact и Expires, дата не просрочена.
  • Ссылки начинаются с https:// и ведут на живые страницы.
  • Если указан Encryption, ключ открывается и проверяется.
  • Есть политика на отдельной странице, внятная и краткая.
  • Письма из канала связи попадают в рабочую очередь, а не в «общий ящик».

Полезные ссылки

Итоги

security.txt — простой шаг, который даёт много пользы. Вы объявляете понятные правила, снижения трения хватает уже в первый же день, а исследователи получают ясный канал связи. Создайте файл, положите его в /.well-known/, свяжите с политикой, добавьте ключ шифрования и автоматизируйте продление Expires. Это займёт совсем немного времени, зато сэкономит его в будущем и поможет исправлять уязвимости раньше, чем они станут новостями.


Ищем уязвимости в системе и новых подписчиков!

Первое — находим постоянно, второе — ждем вас

Эксплойтните кнопку подписки прямо сейчас