惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Vercel News
Vercel News
The GitHub Blog
The GitHub Blog
博客园 - 【当耐特】
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Recent Announcements
Recent Announcements
D
Docker
GbyAI
GbyAI
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
The Cloudflare Blog
雷峰网
雷峰网
A
About on SuperTechFans
小众软件
小众软件
博客园 - Franky
博客园 - 聂微东
F
Full Disclosure
大猫的无限游戏
大猫的无限游戏
C
Check Point Blog
MongoDB | Blog
MongoDB | Blog
G
Google Developers Blog
Microsoft Azure Blog
Microsoft Azure Blog
U
Unit 42
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
V2EX
Engineering at Meta
Engineering at Meta
宝玉的分享
宝玉的分享
aimingoo的专栏
aimingoo的专栏
量子位
P
Proofpoint News Feed
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
罗磊的独立博客
Martin Fowler
Martin Fowler
D
DataBreaches.Net
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
S
Secure Thoughts
Project Zero
Project Zero
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
C
Cybersecurity and Infrastructure Security Agency CISA
T
Tailwind CSS Blog
S
Schneier on Security
Blog — PlanetScale
Blog — PlanetScale
The Hacker News
The Hacker News
Spread Privacy
Spread Privacy
Security Latest
Security Latest
NISL@THU
NISL@THU
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
C
CXSECURITY Database RSS Feed - CXSecurity.com
J
Java Code Geeks

Все публикации подряд на Хабре

Ловим музу за клавиатуру: как айтишнику стать автором Что умеет Midjourney в 2026? Мой немного грустный разбор этого шикарного инструмента Никто не любит писать тесты, но ИИ может исправить это IPv8 выглядит как мечта. Поэтому почти наверняка не взлетит Производители вернули в продажу материнки с DDR3. Что происходит? Управление агентом с телефона через Telegram теперь в KodaCode От координации к лидерству: как меняется роль руководителя разработки Я сделала родителям бизнес вместо пенсии: зарабатываем 70 тысяч, мама не даёт продать В три раза быстрее приемка товара и оптимизация трудозатрат на 73%: как «РСТ-Инвент» помог Gulliver Group ИИ-шечный мир победил? О влиянии искусственного интеллекта на игропром Кремль снижает давление на Телеграмм пока Европа строит интернет по паспорту Как CEO, CTO и CIO за 8 часов собрали ИИ-директора, который умеет держать позицию под давлением Как (не) потерять домен за выходные Вместо 8 разных VPS: как я организовал практику студентам на одном сервере Почему твой Open Source проект не замечают? R&D: искусство управления неопределенностью в разработке AI-дефляция: вакансий для разработчиков больше, а рост зарплат — худший за 15 лет Мы отдали управление роботами OpenClaw. Что из этого вышло Галактический ID: система идентификации для всех форм разумной жизни Шесть основ бизнес-анализа: начинаем с вопроса «Кто в игре?» Код-ревью, в котором дело не в коде Данные переехали. Команда — нет Системной подход к сдаче OSWE в 2025 Почему комната управления реактором покрашена в цвет морской пены 4 YAML-файла вместо PySpark: как аналитикам строить пайплайны без разработчиков LLM-агент для поиска свободных доменов: автоматизируем подбор Когда, зачем и как правильно начинать новую сессию в Claude Code? Как я заставил нейросеть писать макросы для FreeCAD Анатомия ИИ‑агента для подбора персонала. От тысячи резюме к топ‑10 за минуты Опыт разработчика как экономика внимания Автономность как точка невозврата: кто будет субъектом в цифровом будущем Обучение ИИ в «диких» условиях: как рутинные действия превращаются в датасеты Как измерить LLM для задач кибербеза: обзор открытых бенчмарков Где хранить код? Сравнение GitHub, GitLab и Bitbucket Математика объясняет, почему нормальное распределение встречается повсюду Почему ваш FinOps не работает: 12 тезисов от практиков Как подписать проектную документацию УКЭП с использованием бесплатных лицензий Pilot Адаптивное администрирование Sigla Vision Я грузил уран в бочки, а потом 20 лет строил ИТ в атомной отрасли Чем позвонить с Эвереста? История и обзор спутниковой связи. Часть 2 Как языковая модель помогает контролировать качество инструктажей по охране труда в металлургии Как не передать на desktop свой IP в РКН Анатомия SAP Privileges: как устроено управление правами в macOS MoneyDev: Сказка про три главных слова Обновлённый токенизатор видео K-VAE 2.0 от Сбера Как сделать диспетчеризацию дома на 1284 квартиры почти бесплатно Как мы разогнали железную дорогу Мы дали агентам рутину. Теперь надо решить — что делать с освободившимся временем Токсичный контент, промпт-хакинг и защита ИИ — всё о Guardrails для LLM Умный город начинается с точного взгляда: как «Фалькон Тех» меняет пространство к лучшему Навайбкодил приложение для анализа графов Почему Дюну так интересно читать? Упрощаем работу с рутиной или как стать Гендальфом Белым Деконструкция Go: CPU, RAM и что там происходит. Go Assembler база. Часть 1.1 Какие профессии исчезнут из-за ИИ, а какие появятся? И что с этим делать Как мы построили IT-отдел, где хочется расти: архитектурные встречи, прозрачные метрики и книжные подарки Rufler: Делаем из Claude Code автономный рой через один YAML-конфиг Sing-box и белый список приложений Как построить надёжный обмен сообщениями в микросервисах: лучшие практики для enterprise OpenAI строит MLM-пирамиду, а McKinsey и Accenture помогают ей в этом Дом, который не построил Фишер (Часть 2) «Сверхзвуковой математик» против «Вдумчивого логиста»: битва алгоритмов 3D-упаковки Мультимодальные модели – грубый и дорогой инструмент Разговоры ничего не стоят. Код тоже Проверки физических лиц: с кого начнет ФНС Топ-10 бесплатных нейросетей для создания видео в 2026 году Первые слои кода: как наши решения сегодня определяют архитектуру ИИ на десятилетия Разработка нового статического анализатора: PVS-Studio JavaScript Поиск уязвимостей ПО: базовый минимум или роскошный максимум Почему оценка персонала не работает как инструмент управления Как мы разработали ИИ-ассистента и сократили рутину продуктовой команды на 50% Как я ушел из найма, нажарил косточек и продал на маркетплейсах на 168 млн в год Когда 1С:ERP уже внедрена, а нормального производственного плана всё ещё нет Как я сделал Claude мультимодальным, подключив к нему Qwen Omni Как приглашение на вакансию мечты превращается в атаку Infrastructure as Code: философия и лучшие практики IaC Тестируем Yandex Code Assistant на задаче, в которой нужно хранить секреты nxs-universal-chart v3.0: новое поколение универсального Helm-чарта Callback Injection: Техника, которая отправила Microsoft Defender в глухой нокаут «Все идеи на стол»: митап как способ вывести проект из тупика Сегодня я узнал нечто новое о GPU благодаря багу в своей игре Как заставить LLM ̶ ̶г̶а̶л̶л̶ю̶ ̶ эволюционировать Карта событий как фундамент аналитики: практический кейс для E-commerce Что выбрать для AI: x86, ARM или RISC-V? Дайджест железа за март Роль соматических мутаций в развитии аутоиммунных заболеваний: путь к избирательной терапии Mythos от Anthropic — тревожный сигнал для всех, а не только для банков Guardrails для LLM на Java: как приручить промпт‑инъекции и токсичные ответы Green-VLA: как мы собрали VLA-модель для реального антропоморфного робота и не потеряли обобщение Финансовая гонка вооружений: почему умные люди добровольно в ней участвуют Эра ИИ-агентов наступила: выбираем лучшего цифрового сотрудника # Практический опыт внедрения WinCC Redundancy на производственном предприятии Сделал MVP за 3 дня, а потом неделю прикручивал оплату. Оно того стоило? Физика против Маска: почему Starship V3 может оказаться ещё одной катастрофой Нефть Венесуэлы: крупнейшие запасы в мире, но не крупнейшая нефтяная держава JPA 4. Переосмысление Hibernate Почему зеркальная фотокамера Nikon D5 десятилетней давности идеально подошла для миссии «Артемида-2» Проект «Уровень-Спутник» или как мы сделали платформу для гидрологов «Замедлиться, чтобы ускориться»: почему ИИ повышает цену ошибок в требованиях и архитектуре Как с нуля поднять трафик IT-компании на 1657% при бюджете 55 тыс. и выжить Pixel-perfect Downsampling — идеальная отрисовка 50 миллионов точек без потерь
mTLS на практике: от модели угроз до реальных атак на сервер
opensophy (R · 2026-05-20 · via Все публикации подряд на Хабре

Уровень сложностиСредний

Время на прочтение9 мин

Охват и читатели29

Кейс

Введение

Это вторая часть цикла про mTLS. В первой разобрали теорию: как работает рукопожатие, от каких атак защищает и где принципиально бессилен. Здесь — практика. Разберём реальный сценарий: homelab на одном сервере с Traefik и Dokploy. Пройдём путь от модели угроз до конкретных попыток атаковать собственный сервер — с командами и объяснениями, что происходит.

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

Кратко: что такое mTLS и зачем он нужен?

Уже читали первую часть? Пропустите следующий раздел и переходите сразу к Прежде чем открывать терминал.

Mutual TLS(mTLS) — расширение протокола TLS, при котором обе стороны соединения предъявляют и проверяют криптографические сертификаты. Если клиент не предъявляет сертификаты / предъявляет невалидный сертификат, соединение разрывается на транспортном уровне до любого HTTP-взаимодействия.

Основные причины его интеграции в homelab:

  1. Защита «на подступах» (Drop до HTTP).

  2. Защита сервисов без встроенного логин/пароль.

  3. Безопасный доступ без VPN.

  4. «Исключение» из списков сканирования ботами, которые сканируют интернет.

  5. Удобное управление доступом.

Терминология по mTLS

CA (Certificate Authority) — удостоверяющий центр. В случае mTLS организация использует свой собственный CA. Она создаёт корневой сертификат и подписывает клиентские сертификаты. В отличие от публичного TLS, где CA (например, Let’s Encrypt, DigiCert) проверяет владение доменом, mTLS CA полностью под контролем администратора. Вкратце, вы создаёте сертификат, а потом добавляете или передаёте его устройствам, которые должны получить доступ.

Клиентский сертификат — X.509-сертификат, установленный на конкретном устройстве или в браузере.

Приватный ключ — используется при TLS-рукопожатии для доказательства владения сертификатом.

Что mTLS защищает

Тип атаки

Как mTLS блокирует

Эффективность

Man-in-the-Middle (MitM)

Злоумышленник не владеет приватным ключом клиента и не может завершить TLS-рукопожатие

Высокая

Credential Stuffing

Без клиентского сертификата сервер не переходит к HTTP, форма авторизации недостижима

Полная

Brute Force / перебор паролей

Аналогично — нет доступа к HTTP без сертификата

Полная

Phishing (кража пароля)

Даже зная пароль, злоумышленник не может войти без сертификата жертвы

Высокая

Spoofing / Impersonation

Идентичность привязана к криптографическому сертификату, подделать который без CA невозможно

Высокая

Session Hijacking

Сессионный токен может быть привязан к mTLS-сертификату (certificate-bound tokens)

Средняя (зависит от реализации)

L7 DDoS от ботов без сертификата

Боты без сертификата отсекаются на уровне TLS-рукопожатия, не нагружая приложение

Высокая

Обнаружение сервиса (Shodan, Censys)

Сервер в режиме STRICT не возвращает баннеры неавторизованным клиентам; сканер видит ошибку TLS

Частичная

Уязвимости приложения

Без сертификата невозможно как-либо воздействовать на сайт/сервис.

Высокая (до тех пор пока нет у злоумышленника сертификата)

Прежде чем открывать терминал

Перед настройкой нужно ответить на четыре вопроса.

1. Что у вас есть? Нарисуйте схему — пусть даже на бумаге. Какие сервисы выставлены наружу, какие работают только внутри, что с чем общается. В моём случае это выглядело так: один сервер, на нём Traefik как точка входа, за ним Dokploy на порту 3000, PostgreSQL и Redis внутри Docker-сети, наружу смотрят только порты 80 и 443.

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

3. Что произойдёт, если взломают? Это определяет уровень паранойи. Личный homelab с экспериментами — одно. Панель управления, где лежат production секреты клиентов — совсем другое.

4. От кого защищаетесь? Три реальных уровня угроз: случайный бот/сканер (самый частый), целевая атака (кто-то конкретно хочет попасть именно на сервер), инсайдер (человек, у которого уже есть доступ). mTLS отлично справляется с первым уровнем, частично со вторым, и никак с третьим.

Это обязательные вопросы.

Могут возникнуть и другие вопросы — например, подойдёт ли это под ваш стек? Разберём основную проблему, с которой вы столкнётесь: это reverse proxy и его поддержка mTLS. Нужно найти прокси с полноценной поддержкой mTLS. Какой реверс-прокси подойдёт лучше — смотрите самостоятельно для вашего сервера. При выборе reverse proxy стоит обратить внимание на следующее:

1. Механизм обновления сертификатов и CRL

Умеет ли прокси обновлять данные без перезагрузки (Hot Reload). На что смотреть: если у вас много сертификатов, «reload» конфига (как в классическом Nginx) может вызвать кратковременный скачок нагрузки или микролаги. И правильно ли работает «отзыв сертификатов» (Certificate Revocation). В нашем случае у Traefik нет поддержки Certificate Revocation (получается так: вы сделали отзыв сертификата, но он всё ещё работает). Итог: делаем костыльное решение. Как пример рабочего костыльного решения — создание отдельного промежуточного CA для каждого клиентского сертификата.

2. Поддержка OCSP Stapling

Проверка сертификата по огромным спискам CRL (файлам) — это медленно. Проверьте, умеет ли прокси сам запрашивать эти данные и кэшировать их.

3. Глубина проверки mTLS (Client Auth)

Иногда просто «проверить подпись» недостаточно. Обратите внимание, может ли прокси: проверять Certificate Chain (цепочку доверия) до определённого корня; проверять SAN (Subject Alternative Name) или специфические поля в сертификате клиента для маршрутизации; извлекать данные из сертификата и пробрасывать их в заголовки (X-Client-Cert-DN) бэкенду. (Может быть что-то ещё.)

4. Производительность шифрования

TLS требует ресурсов CPU. Это значит, что нужно правильно настроить прокси (и/или стек защиты), чтобы при каждой, скажем так, «попытке подключения» к серверу у нас не было сильной нагрузки и были защита и ограничения на попытки подключения, т.к. если у нас будут попытки DoS/DDoS-атак на TLS, то, соответственно, будет нагрузка на сервер = краш сервера.

5. Наблюдаемость (Observability)

Вы должны видеть, почему соединение разорвано. Хороший прокси должен давать детальные метрики: сколько ошибок TLS, сколько отказов из-за истекшего срока, сколько из-за отозванного сертификата.

Это обязательные требования к mTLS. Если какой-то из пунктов не работает — это проблема, и её придётся обходить костылями.

Реальный сценарий

Мини-homelab для управления Docker и иных сервисов/инструментов с GitHub и др.

Ниже скриншот, где уже выбрали и протестировали этот стек на устойчивость к типичным атакам, но минусы, конечно, тоже есть.

Протестировав достаточное количество атак, могу сказать вкратце, что при текущем стеке единственный вариант атаки, который я нашёл, — это DoS/DDoS на TLS и кража сертификатов. (Самоподписанный сертификат не пройдёт, если CA настроен правильно — сервер принимает только сертификаты, подписанные именно твоим CA. Мы это тестировали — без правильного cert соединение рвётся на handshake.)

Немного о стеке: Dokploy выступает как платформа для управления Docker и репозиториями (и другими сервисами). Webmin планируется ставить как инструмент управления самим сервером (не полноценно, но всё же), поэтому он присутствует здесь, но с предупреждением: доступ в интернет нужно либо очень хорошо защищать (для Webmin), либо не открывать вообще. Также, наверное, стоит упомянуть, что в этом сценарии все инструменты, сервисы и контейнеры должны быть под mTLS, т.к. это homelab, где доступ есть только у одного человека с 1–3 устройств условно (телефон, ПК и ещё что-нибудь для доступа к своим сервисам).

Минусы у этого стека тоже есть. Например, если отказаться от Traefik (ну, захотели поставить Nginx), то стоит отказаться и от Dokploy из-за его нативной интеграции с Traefik (часть функций не будет работать). Поэтому стоит, опять же, учитывать при «построении сервера», что вы получаете и что теряете.

Безопасность

Мы переходим к самому интересному — проверке защиты на базе нашего сценария. Какие инструменты стоит взять и что проверять?

Самое главное — фаерволл, и смотрим, что у нас доступно из интернета: смотреть рекомендую через nmap. В основном всё должно быть закрыто, и открыты только 80/443 порты. «Специфические порты» — это порты SSH или др. порты для чего-либо — стоит подумать, как защищать. В моём случае я не пользуюсь SSH, мне достаточно 80/443. Docker управляет iptables напрямую и обходит UFW (или другой фаерволл). Это значит, что даже если UFW настроен правильно, Docker может открыть порт наружу через свои собственные правила, и UFW об этом не узнает. Поэтому блокировать нужно через цепочку DOCKER-USER — это надёжный способ закрыть Docker-порты. Пример ниже:

# Разрешить Docker-сетям и localhost
iptables -I DOCKER-USER 1 -p tcp -s 172.16.0.0/12 --dport 3000 -j ACCEPT
iptables -I DOCKER-USER 2 -p tcp -s 127.0.0.1 --dport 3000 -j ACCEPT
# Заблокировать всем остальным
iptables -I DOCKER-USER 3 -p tcp --dport 3000 -j DROP

# Сохранить правила чтобы не слетели после перезагрузки
apt install iptables-persistent -y
netfilter-persistent save

Как проверить, какие порты открыты после того, что сделали выше? Используются nmap и следующие команды:

# Быстро – топ 1000 портов
nmap --top-ports 1000 ваш-ip

# Полная проверка всех 65535 портов (займёт ~2 минуты)
nmap -p- -T4 ваш-ip

В нашем случае результатом после настройки будут открыты только 80/443 порты.

Работает ли mTLS?

Убедитесь в первую очередь, что все возможности работают правильно: правильно создаётся сертификат, отозванный сертификат не работает и т.д., и т.п. — всё, что связано с mTLS.

Правильно ли вы настроили доступ к сервисам? В идеале сервер не должен отвечать без сертификата вообще. Пример: добавили на свой сервис / на свой домен mTLS-доступ — сервис без mTLS не ответит. Правильно. Но если сделать запросы на IP вашего сервера, то он ответит, потому что не закрыт mTLS. Это неправильно, может быть дырой в безопасности, и её обязательно нужно закрыть!

Как закрыть такую дыру?

В моём сценарии я добавил catch-all роутер, который будет отклонять все запросы не по домену, и применять mTLS глобально на entrypoint + firewall.

Попытки сделать атаки. Вот варианты, которые использовались для атаки на сервер:

  • Доступ по голому IP — должен вернуть 403.

curl -sk -o /dev/null -w "%{http_code}\n" https://ваш-ip

Объяснение: отправка запросов на IP, минуя домен, проверка, что сервер не отвечает без домена. Итог: 403. Означает, что соединение есть, но доступ запрещён.

  • Подмена Host заголовка — должен вернуть 421.

curl -sk -o /dev/null -w "%{http_code}\n" \
  -H "Host: ваш-домен" https://ваш-ip

Объяснение: обращаемся к IP, но подделываем заголовки, чтобы проверить, нельзя ли обойти mTLS, просто указав нужный домен в заголовке. 421 означает, что сервер потребовал прямое соединение.

  • Домен без клиентского сертификата — должен оборвать TLS.

curl -vk https://ваш-домен

Объяснение: обычная проверка, можно ли получить доступ без клиентского сертификата.

  • TLS-даунгрейд — должен отклонить соединение.

curl -sk --tls-max 1.2 -o /dev/null -w "%{http_code}\n" https://ваш-домен
curl -sk --tls-max 1.1 -o /dev/null -w "%{http_code}\n" https://ваш-домен

Объяснение: делаем попытки принудительно договориться об использовании старых версий TLS, сервер должен принимать только TLS 1.3.

  • Перебор путей — все должны вернуть 000 (TLS рвётся до HTTP).

for path in /admin /.env /api /dashboard /health /metrics; do
  code=$(curl -sk --max-time 3 -o /dev/null -w "%{http_code}" https://ваш-домен$path)
  echo "$code $path"
done
  • Traefik внутренние эндпоинты – все должны вернуть 403.

for path in /dashboard/ /api/ /api/rawdata /metrics /ping; do
  code=$(curl -sk --max-time 3 -o /dev/null -w "%{http_code}" https://ваш-ip$path)
  echo "$code $path"
done
  • Flood без сертификата.

# wrk – HTTP/2 flood
wrk -t4 -c100 -d30s https://ваш-домен
# Ожидаемый результат: 0 requests, ~2000+ read errors

# h2load – HTTP/2 rapid reset
apt install nghttp2-client -y
h2load -n 100 -c 10 https://ваш-ip
# Ожидаемый результат: 100 failed, 0 succeeded

Объяснение: с помощью wrk и h2load мы создаём множество одновременных подключений без сертификата, это проверка на поведение сервера под нагрузкой. Все соединения должны получить статус failed.

  • Заголовки ответа:

sudo curl -sk \
  --cert /path/to/client.crt \
  --key /path/to/client.key \
  -I https://ваш-домен | grep -iE "server|x-powered|strict-transport|x-frame"

Это всё стоит делать с другого устройства (да хоть с телефона через Termux). И пройтись по рекомендациям от TLS-аудита.

apt install testssl.sh -y
testssl https://ваш-домен

Что должны увидеть в идеале:

SSLv2/3, TLS 1.0/1.1/1.2  not offered
TLS 1.3                    offered (OK)
Forward Secrecy            offered (OK)
Heartbleed, POODLE, BEAST  not vulnerable
Rating: A+

Осталось только проверить, что работает Fail2ban. Возможно, есть и другие векторы атак (именно для этого стека), поэтому это прям… минимум для проверки. Можно ещё через DAST-инструменты найти какие-нибудь проблемы на сервере, но будьте осторожны при их использовании! (Что такое DAST-инструменты, можете изучить тут).

Заключение

Мы имеем хорошую защиту с минимальным потреблением ресурсов. Через Dokploy-панель можно смотреть мониторинг и запросы на сервер. По результатам тестов стек держит всё, что удалось «бросить»: запросы без сертификата, подмену заголовков, TLS-даунгрейд, перебор путей — всё рвётся на handshake. Traefik не отдаёт внутренние эндпоинты, по голому IP — 403, домен без сертификата — обрыв TLS.

Два реальных вектора, которые остаются, — DoS на TLS-рукопожатие и кража сертификата. Частично это закрывается через Fail2ban и rate limiting, но полной защиты нет. Из ограничений стека: Dokploy нативно завязан на Traefik — захотите сменить прокси, придётся менять и платформу. Webmin присутствует, но в интернет его лучше не открывать совсем. Стек рассчитан на одного человека с 1–3 устройствами — на команду адаптировать тоже возможно.

В конечном счёте mTLS — это инструмент. Как любой инструмент, он работает хорошо только тогда, когда вы понимаете, зачем берёте его в руки.

Источники и рекомендации

© 2026 ООО «МТ ФИНАНС»