Хроники разваливающихся интернетов. Я, в силу ряда причин, использую DNS-резолвер, который установлен за пределами Рунета. С некоторых пор я заметил, что ряд вспомогательных сервисов для аккаунта Google – недоступны из браузера, из моей локальной сети. А я всё ещё использую для ряда задач почту Google – так исторически сложилось, тем более, что, в отличие от того же “Яндекса”, Google мне пока что эту историческую почту и кучу прочих сервисов под моим доменом (из Рунета, заметьте) предоставляет бесплатно, как ни странно; не знаю, долго ли ещё так будет, но пока что – так; недостатки там тоже есть, кто бы сомневался, но это другая история: а сервис, как минимум, никто за эти десятилетия у меня не отобрал – очень существенный плюс Google, по нынешним временам-то.

Вернёмся, впрочем, к доступности.

Итак, я заметил, что какие-то сервисы через HTTPS недоступны, а они необходимы для нормальной работы веб-интерфейса (там всё управление – через веб). Логичное предположение: так как мой резолвер приходит на авторитативные серверы Google из “иностранной сети”, ему DNS Google отдаёт другие IP-адреса, а именно – адреса, предназначенные для соответствующего региона; и узлы под этими IP-адресами – недоступны из российских сетей. Почему это влияет? Потому что браузером-то я подключаюсь из российской IP-сети. Где именно соответствующий трафик забанен – я уже не стал разбираться: сейчас подобное разбирательство – легко превращается в длительное исследование, так как понять, “что-как-где-почему”, довольно сложно: сети окончательно стали мутными на прикладном уровне. Да, я делал бы ставку на то, что забанено на российском транзите; но, к сожалению, тут нельзя полностью исключать и сторону CDN Google – вообще говоря, агрессивная геобалансировка на стороне крупнейших провайдеров была известна и раньше, иногда, скажем, такая блокировка может быть побочным эффектом маршрутизации для anycast-адресов (отдельная история).

В общем, я просто добавил на сторне своего DNS-резолвера функцию отправки подсети-источника DNS-запроса в ECS, но только для доменов внутри зоны google.com, чтобы авторитативные DNS-серверы на той стороне видели целевой IP-префикс запроса. В Unbound (весьма рекомендую, кстати) избирательная поддержка ECS легко включается. После того, как в запросы добавились ECS – IP-адреса в ответных A-записях стали приходить другие, а сервис Google – тут же заработал из локальной сети. Да, откровенно говоря, не могу исключить, что это совпадение, но посмотрим: в других, – более прозрачных, но аналогичных, – случаях, с которыми я сталкивался, подход с перенастройкой резолвера срабатывал эффективно.



Комментировать »

У меня в GitHub тоже есть аккаунт, которым, впрочем, я почти не пользуюсь. Но это не отменяет важности GitHub, конечно. Я под своим там аккаунтом довольно давно опубликовал реализацию шифра “Кузнечик” с оптимизацией на ассемблере Go (гораздо более новая версия, с поддержкой ARM64, есть у меня на сайте, если это вообще кому-то нужно). Кроме того, на GitHub я как-то выложил Runic32 – реализация Base32 на алфавите из англосаксонских рун (“футарк/футорк”, условно говоря). Этот проект является шуточным – потому что как-то зашёл разговор о том, что “TLS-сертификаты отображаются какими-то крючками”: ну, вот, при помощи утилты runic32 можно сертификаты записывать прямо рунами (если есть Unicode).

При этом, как ни странно, но аккаунт в данной “социальной сети” GitHub (известная филологическая английская шутка) я завёл для того, чтобы написать в один из проектов IETF, которая IETF, следуя странной моде, перенесла основную часть своей деятельности по подготовке стандартов в GitHub (спорное решение, мягко говоря). К сожалению, реальность такова, что, фактически, сейчас без GitHub мало что из “рабочих вопросов”, для меня, обходится: начать с того, что с GitHub среди разработчиков принято тянуть очень много из критически важных библиотек, а какие-то библиотеки – просто негде взять удобным способом: скажем, вот полезнейшая CIRCL от Cloudflare.

Я сам сторонник того, чтобы написать всё своё. Да, именно так, и большой плюс – если на ассемблере. Однако, такое нынче – это из области фантастики. В нынешней ситуации – подобный подход не находит понимания в широких массах современных разработчиков на ЯВУ, а приводит только к смешкам и попыткам кидаться штампами вроде “зачем нам изобретать велосипед”, при том, что разработка с нуля – это не изобретение велосипеда, а попытка велосипед сделать самостоятельно, научившись делать велосипеды, а не педалировать чужие. Ну да ладно, тема для другой записки. (Кстати, например, сейчас даже весьма квалифицированный, – реально, – разработчик (не кодер) – ассемблера не знает, да и требовать такого знания – это считается лишним.) В общем, поскольку с таким положением приходится мириться, то и важность “социальной сети” GitHub становится совершенно бесспорной и – растёт дальше. Проблема, конечно, что это централизованный сервис, который, в рамках “битвы за банхаммер”, все хотят отломить. Но, к сожалению, это не уменьшает практической важности. Более того, во многих крупных проектах нынче только через GitHub принимают сообщения об ошибках и прочие технические запросы, что ещё усиливает центральное положение GitHub.



Comments Off on Про GitHub

Кстати, насчёт “быстрых” TLS-сертификатов для IP-адресов, которые подходят для веб-сайтов без доменных имён. Я уже некоторое время тестирую схему с таким сертификатом на сайте под IP-адресом https://185.39.19.199/.

Напишу, как там что настроено (это виртуальная машина, понятно). ОС Debian 13, веб-сервер – nginx 1.26.3, из пакетов Debian; я установил актуальную версию 5.6.0 утилиты certbot из snap (предварительно поставив snap, конечно) и настроил профиль аккаунта с использованием директории web-root, которую обслуживает nginx для хоста по умолчанию. Поскольку нужно принимать и обрабатывать HTTP по IP-адресу, в nginx я настроил единственный блок server для произвольных имён (default_server на 80 и 443, кроме того, на всякий случай, заведомо недоступный “_” в server_name). Пути к сертификату и ключу – указывают туда, где ссылки на них выкладывает certbot: /etc/letsencrypt/live/185.39.19.199/fullchain.pem.

Сама утлита certbot запускается по таймеру Systemd, а чтобы nginx подхватывал новый сертификат после его выпуска, я добавил в /etc/letsencrypt/renewal/185.39.19.199.conf строку “renew_hook = systemctl restart nginx”, блок “[renewalparams]”.

Собственно, это всё: такая конфигурация работает, а новые сертификаты выпускаются автоматом до истечения действующего. (Один из старых сертификатов я даже отозвал, в порядке эксперимента, указав причину отзыва superseded – это сработало, но выяснилось, что, судя по CRL, практически никто при отзыве не указывает код причины.)

Да, кроме IP-адреса я ещё завёл на тот же сервер доменное имя вида 185.39.19.199.zone, чтобы протестировать заказ сертификатов для “смешанных” имён: и IP-адрес, и DNS-имя. Это тоже работает – можете проверить по составу TLS-сертификата:

DNS Name: 185.39.19.199.zone
IP Address: 185.39.19.199 

Схема та же, как и с IP-адресом, но первоначально нужно указать при вызове certbot доменное имя при помощи опции -d (дополнительно к IP-адресу). Проверка DCV будет выполнена и для IP-адреса, и для доменного имени, а сертификат выпустится с двумя именами в блоке SAN.



Комментарии (1) »

DNSSEC строится на механизмах цифровой подписи и на иерархии криптографических ключей. Открытые ключи публикуются в DNSKEY-записях. Подписи вычисляются для адресной информации, опубликованной в зоне. Значения подписей публикуются в RRSIG-записях. Ключей и, соответственно, DNSKEY-записей в DNS-зоне может быть несколько. Чтобы доверенным образом проверить подпись, резолвер должен выбрать подходящий ключ. Чтобы упростить поиск подходящего ключа – в RRSIG-записях указывается 16-битный тег, соответствующий ключу. Это и есть тег ключа DNSSEC. (Тег ключа используется также в DS-записи, которая обеспечивает другой важнейший аспект: делегирование в DNSSEC, но ниже речь пойдёт только про RRSIG.)

Значение тега представляет собой простейшую “контрольную сумму” – то есть, сумму октетов DNSKEY-записи, выполненную в определённом порядке (чётные/нечетные и т.д.). Очевидно, что используемый алгоритм вычисления тега тут вообще не имеет особого значения – в теге всего 16 битов, а в ключе, как минимум, 256 битов: коллизии тут всегда будут достигаться легко.

Практический смысл добавления некоего “алгоритма суммирования” несколько тёмен. Понятно, что сумма позволяет побороть варианты, когда в каких-то криптосистемах некоторые части в записи ключей принципиально одинаковые. Но это, обычно, не так. Поэтому можно было бы с почти тем же успехом, например, брать два байта на нечётных средних позициях записи непосредственно ключа (примерно так и было сделано для тегов алгоритма подписи RSA/MD5); да, ещё нужно учитывать флаги ключа, но и это не сильно влияет на практику. В общем, как бы там ни было, но DNSSEC сейчас использует теги, вычисляемые как сумма.

Если теги разных ключей в зоне не совпадают (обычно, в добропорядочной зоне, это так и есть, но см. ниже), а в RRSIG – указано верное значение, то, конечно, это ускоряет процесс выбора ключа и проверки подписи. Проблема в том, что вычислительные затраты на проверку подписи по “пробному ключу” сильно меньше, чем затраты на обработку специально неверно сконфигурированной зоны с совпадающими тегами ключей. И ещё хуже, что неверная интерпретация свойств тегов регулярно приводит к масштабным сбоям в практике DNSSEC – отламываются целые большие TLD (это было в зоне .RU, это же теперь было и в .DE, которая в несколько раз больше).

Вообще говоря, выбор ключа при валидации записей, в имеющейся конфигурации DNS, так или иначе, но проводится при помощи “пробных операций проверки подписи”: дело в том, что RRSIG-запись считается доверенной только в том случае, если в зоне нашёлся хотя бы один доверенный ключ, которым удалось успешно проверить подпись. Если ключей не нашлось, то вообще не важно, какие были значения у тегов и RRSIG – доверенной информация в DNS-зоне быть уже не может.

Естественно, штатный способ выбора ключа состоит в сравнении тегов: если в зоне единственный ключ с совпавшим значением тега, и этот ключ не даёт доверенной подписи для заданной RRSIG-записи, то, понятно, другие ключи можно не проверять. Почему? Потому что спецификация требует, чтобы тег, указанный в RRSIG, совпадал с тегом ключа. Заметьте, что нигде не сказано, что соответствие должно быть один к одному – тег-ключ. Но даже в случае такого совпадения, это всё равно будет пробная проверка подписи – просто, в штатной конфигурации, используется единственная итерация. Всё потому, что тег не обязательно соответствует одному ключу.

Из обратной ситуации, то есть, из того, что ключи должны соответствовать тегам, но разные ключи могут иметь одинаковый тег, и выводится DoS-атака: в зоне может быть несколько ключей с одинаковыми значениями тега и резолвер должен перебирать эти ключи для проверки RRSIG, которая теперь ссылается единственным тегом на множество ключей. При этом, RRSIG-записей может быть много. И криптосистем тоже может быть несколько. Это известная DoS-атака под названием KeyTrap (CVE-2023-50387).

А из обобщения принципа, что теги недопустимо использовать в качестве идентификаторов ключей при вычислении подписи (а лишь как первый шаг, сужающий набор для перебора, при проверке подписи) и публикации ключей в DNS-зоне, выводится угроза штатной подмены ключа в процессе подписывания зоны: из-за того, что схему ломает единственное совпадение пары значений тегов, вероятность совпадения для разных ключей, результатом которого будет сбой – очень и очень велика. То есть, в схеме подписи, для её вычисления, использовался один ключ, но где-то рядом сохранился второй ключ, с совпавшим тегом, и в зоне будет опубликован этот второй, неподходящий ключ. Но неподходящий он – по значению подписи, не по значению тега – значение тега-то, как раз, подходит под RRSIG, а поэтому простая проверка на соответствие тегов, на уровне, что в зоне есть ключи с тегами из RRSIG, успешно пройдёт. К сожалению, из-за особенностей DNSSEC, такая проверка имеет весьма небольшую пользу: ключи должны строго и по тегу сходиться, и по подписи.



Комментировать »

В DENIC опубликовали некие сведения о причинах недавней поломки DNSSEC в зоне .DE (DENIC – оператор). Как ни странно, но, похоже, причина именно в некорректном использовании тегов ключей. Я как раз в прошлой записке по этой теме такое и предположил: “возможно, тоже перепутали ключ из-за совпадающих тегов”. Выходит, что снова использовали теги для индексирования ключей в процессе подписи. Теги – могут запросто совпадать у разных ключей. К сожалению, как это нередко бывает, в опубликованном пояснении формулировка расплывчатая:

Consequently, for the same “key tag” (33834), three different key pairs were generated instead of a single one, of which only the public key of a single pair was stored in the DNSKEY RR, meaning that only about a third of the RRSIG RRs could be validated. (В результате, для одинакового “тега ключа” (33834) были сгенерированы три разных ключевых пары вместо одной, из которых только открытый ключ единственной пары был размещён в DNSKEY-записи, что привело к тому, что только треть из RRSIG-записей могли быть валидированы.)

Ну, то есть, можно предположить, что раз только треть валидировалась, значит – остальное подписывалось другими секретными ключами, из пар, имевших один и тот же тег открытого ключа, а ПО ссылалось на ключи по значению тега (чего делать при подписывании нельзя категорически). Тут может возникнуть сомнение: как же тогда так получилось, что для трёх разных ключей совпал тег? Да, чтобы тег заведомо совпал для ключей, сгенерированных на небольшом интервале времени, ключи нужно специально перебирать (но и это нетрудно – там всего-то 16 битов в теге). Но дело в том, что ключи подписи зоны постоянно заменяются при штатной работе, так что эти пары с совпавшими тегами скорее всего были старыми ключами, сгенерированными ранее, и не удалёнными из системы. Теги же совпадут с большой вероятностью, так или иначе, если просто генерировать ключи штатным образом – только будет несколько дольше по времени: вероятность там много больше, чем 1/65535, как продолжают думать, – ведь это типовое воплощение парадокса дней рождения.

Собственно, в недавней записке об аварии DNSSEC в .DE я поэтому и упомянул конфликты тегов ключей DNSSEC, которые теги используют не по назначению. Цитата:

В DNSSEC выбрана неудачная система тегирования ключей при помощи 16-битных номеров, которые, понятно, то и дело совпадают для разных ключей; данные теги нельзя использовать в качестве индекса при выборе ключей для подписи, об этом написано в RFC, об этом много писал и говорил я, и не только я, но теги всё равно регулярно используют с такой целью; однако насчёт данного случая с DE – не факт, что в этом была проблема.

Оказалось – в этом и была проблема. Что тут ещё сказать? Бывает, конечно: ведь с пониманием сложных процессов – сейчас трудности везде.



Комментировать »

В домене .DE на некоторое время сломались подписи DNSSEC. Сейчас уже пишут, что починили. Возможно, тоже перепутали ключ из-за совпадающих тегов. (Лирическое отступление: в DNSSEC выбрана неудачная система тегирования ключей при помощи 16-битных номеров, которые, понятно, то и дело совпадают для разных ключей; данные теги нельзя использовать в качестве индекса при выборе ключей для подписи, об этом написано в RFC, об этом много писал и говорил я, и не только я, но теги всё равно регулярно используют с такой целью; однако насчёт данного случая с DE – не факт, что в этом была проблема.)

Интересна тут реакция Cloudflare, как оператора одного из самых распространённых в этих интернетах сервиса DNS-резолвинга – 1.1.1.1: в Cloudflare, после локализации ошибки на стороне DE, валидацию DNSSEC для этой зоны просто отключили. Ну, то есть, очередной пример реальной ценности DNSSEC в современой глобальной DNS: если что не так, то систему валидации принято отключать; но, конечно, не просто так отключать, а информированно отключать.

Есть даже RFC 7646, который, кто бы мог подумать, прямо предписывает так делать. Естественно, речь тут идёт об операторах DNS-сервисов, которые могут убедиться, что, мол, “это не атака подмены”, а это DNSSEC сломали сами администраторы ключей, очередной раз. Хотя, строго говоря, достоверно определить, что подписи стали расходиться не из-за атаки, а из-за ошибки – весьма и весьма сложно: атака могла быть на уровне оператора реестра, например. Может ли тут что-то с уверенностью – и, главное, быстро, – сказать внешний наблюдатель, даже если он оператор резолвера? Ну, это вряд ли. Остаётся полагаться на ответы оператора реестра и, что называется, кликать виртуальную универсальную кнопку “Всё равно продолжить” для всех пользователей своего “валидирующего” резолвера. Такая вот нынче стала на практике эта технология – DNSSEC. Ничего не поделать.



Комментировать »

Хроники разваливающихся интернетов и проблем с диагностикой разваливания. Понадобилось тут проверить один технологический артефакт в связке DNS+TLS, для чего я поднял виртуальный сервер у одного из провайдеров (не буду назвать, это не важно) и установил там BIND в качестве авторитативного DNS-сервера для тестовой зоны. И вот – BIND работает, а TXT-записи, в ответ на DNS-запросы снаружи, не приходят. Локально, на том же хосте, – приходят ответы TXT. С другими запросами – SOA, NS – всё хорошо, ответы приходят и наружу. TXT – не приходит. Но не приходит – по UDP. А зато по TCP – приходит.

Собственно, тут-то и нетрудно было догадаться, что это, видимо, какой-то фильтр где-то на промежуточном узле. Просмотр дампов трафика гипотезу подтвердил: на машину с DNS-сервером внешние DNS-запросы в UDP приходят, а ответы – уходят. Но вот дальше – проходят только ответы не с TXT. Выяснение этого, конечно, заняло какое-то время – изначально выглядело так, как если бы что-то сломалось в BIND.

Видимо, так вот решили “гибко” (может, даже с новомодным ИИ) побороться с источниками DoS-атак: широко известно, что TXT-записи являются носителем трафика для DoS-атак, так как эти записи могут содержать большой объём данных, а если “подспуфить” UDP, подставив чужой адрес, то большие пакеты поедут в сторону этого, чужого, адреса. Другие типы записей – обычно не считаются носителями трафика для DoS.

Да, строго говоря, фильтровать-то нужно по “подспуфленным” UDP, а не по единственному признаку TXT – подобная грубая фильтрация DNS-ответов приводит к тому, что в такой сети невозможно держать авторитативный NS: без TXT сейчас никуда – и почта их использует, и валидация при выпуске TLS-сертификатов. Зато получилась очередная практическая демонстрация того, как эти интернеты становятся непрозрачными даже не только на уровне протоколов, но на уровне некоторой “внутрипротокольной” семантики. Да, конечно, такая вот, – типа, “гибкая и интеллектуальная”, – фильтрация была и раньше, в том числе, по DNS-ответам. Это просто свежий практический пример.

Кстати, хотя есть и другие варианты DNS-записей, которые могут содержать большие объёмы ответов – см. DNSSEC, например, – но с TXT – проблема более чем известная: в зонах бывает много TXT, скажем, в google.com сейчас 13 записей почти на килобайт, и это – ещё совсем не много; кроме того, что-то ещё и забывают почистить, так что записи накапливаются. Естественно, извлекать откуда-то из целевой зоны толстый набор TXT-записей может и открытый рекурсивный резолвер, не обязательно держать авторитативный сервер: фильтруется оно одинаково.



Комментарии (2) »

Кстати, занятно, что TLS-сертификаты и удостоверяющие центры в вебе уже скоро могут перейти на вариант с хеш-деревьями и криптосистемами с постквантовой стойкостью, а в DNSSEC всё ещё будут планировать переход на ECDSA. Я про эту замену в корне DNSSEC писал недавно.

При этом, в прочих областях, – например, в TLS, – переход на постквантовые криптосистемы (ключи и подписи которых в DNS не очень-то хорошо влезают) мотивируется возможностью запуска квантового алгоритма Шора на гипотетическом квантовом компьютере. Однако, если с этой точки зрения, то имеющаяся в корне DNSSEC криптосистема RSA, с практической разрядностью, – заметно более стойкая к квантовому взлому, чем ECDSA, на которую планируют в корне DNS перейти.

Вот тут и возникает “странная дилемма DNSSEC”: ECDSA, без сомнения, вариант прогрессивный, по сравнению с RSA, но против алгоритма Шора – стойкость имеющейся RSA выше (2048 бит против 256), а криптосистемы с постквантовой стойкостью – тут пока и не рассматриваются.



Комментарии (2) »

Сейчас много околотехнических обсуждений по теме методов определения того, пришёл ли веб-клиент на некий крупный веб-сервис “c VPN или без VPN”. Оставим за скобками набравшую сейчас популярность трактовку того, что такое VPN – термин обобщили до невозможности. Но в технической стороне процесса “определения” сетевых настроек есть пара занятных моментов, которые как-то пропускают.

Момент первый: измерение параметров времени для TCP-соединения. Например, к некоторому веб-сервису подключается клиент, скажем, браузер. При помощи выполнения некоторых скриптов не очень трудно померить время “сетевой задержки” между средой веб-страниц этого браузера и серверной средой. То есть, это будет время доставки запроса, измеренное от контекста DOM в браузере до веб-сервера. Предположим, это 50 ms. Но это всё по HTTP, а HTTP-соединение использует TCP.

TCP-соединение устанавливается не с браузером, а с логически ближайшим к серверному сетевому стеку узлом. Это может быть клиентский компьютер, то есть, ОС на этом компьютере. Но может быть и выходной узел, выполняющий трансляцию адресов, например. Обычно – именно так и есть: клиентский компьютер редко стоит прямо за маршрутизируемым IP-адресом. Тогда, если измерять и задержку в браузере, и задержку на серверном TCP, то получится, скажем, что, в рамках одной логической HTTP-сессии, TCP-задержка – 10 ms, а браузерная задержка, до DOM в HTTP-клиенте, – 50 ms. Большая разница – 40 ms. Это означает, что от клиента транслированные запросы ещё где-то там внутри долго ходят, пока доберутся до выходного узла, который к нам по TCP подключился.

Если же выходной TCP-узел примерно совпадает с логическим узлом, где работает клиентский браузер, то разница между двумя задержками будет минимальной, например: 10 ms TCP и 11 ms – браузерная задержка, читай – Javascript в DOM-контексте. Здесь под “примерно совпадает” имеется в виду, что между клиентским компьютером и выходным узлом нет большого сетевого плеча: компьютер и выходной узел стоят технически рядом (простейший случай: локальный пограничный “роутер” с NAT и подключенный к этому “роутеру” по локальному порту компьютер в локальной IP-сети над Ethernet-ом).

Естественно, измерять задержки TCP-стека для веб-сервиса (не веб-сервера) – несколько сложнее, чем померить что-то внутри веб-логики. Для таких измерений нужно зацепить “щупы” прямо в сетевой стек, причём, на входном узле, а не на бэкенде, куда проксируются HTTP-запросы. Очевидно, что на “веб-уровне”, даже для сервера, TCP в таких деталях не виден. Но измерять всё равно можно – это не суперсложная задача, и решение вполне под силу специализированной компании, сохранившей инженерный подход среди своих разработчиков. Мы же тут, как раз, речь ведём о крупных профильных компаниях, где, вполне возможно, понимающие инженеры есть – верно?

Понятно, что сравнение задержек по времени на уровне браузерного движка с задержками на уровне TCP-стека не является каким-то волшебным зеркалом, которое всё показывает: большие задержки бывают при использовании радиоканалов, из-за перегруженного оборудования, из-за потерь пакетов на стороне клиента и т.д. Тем не менее – фактор это достаточно важный, чтобы о нём не забывать.

Момент второй: геометрия сетевых подключений. Если наш гипотетический веб-сервис имеет только одно подключение к общему Интернету, – которое называют “аплинк”, – то этот веб-сервис не может различить пути поступления сетевых пакетов извне в локальную сеть, в рамках какой-то веб-сессии. Ну, как не может – путь для таких пакетов тут один, потому что один “аплинк”. Соответственно, различать нечего. Однако в совсем крупных компаниях, связанных с веб-сервисами, есть несколько подключений, несколько “аплинков”, своя автономная система (или несколько) и свой центр управления сетью, населённый инженерами NOC.

Для опытного инженера NOC, IP-адрес – это сетевой номер, идентификатор, а не “интернет-узел”. С точки зрения физической организаци сети, IP-адрес может указывать куда угодно, а доставка IP-пакетов – просто происходит на другом уровне, чем работает сама вверенная сеть. Поэтому IP-пакеты можно различать по физическим портам коммутаторов или по логическим маршрутам, которые ниже IP и связаны с внутренним устройством сетей оператора (см. MPLS и пр.). Так что для IP-пакетов, с разными адресами источника, и разными правилами, могут использоваться разные порты подключения – эти пакеты, проще говоря, приходят “с разных сторон”, что создаёт внутренний различительный признак. Как ни странно, но этот признак зависит от внешних факторов (где какие фильтры, кто к кому подключен и пр.).

Сюда же попадает и повсеместная путаница, связанная с распределением блоков IP-адресов (префиксов). У всякого IP-префикса есть администратор – автономная система (AS). Это верно. Но ещё есть маршрутизация и BGP. И вот в рамках BGP, технически, быть источником (origin) для данного IP-префикса может любая (подчёркиваю: технически – любая, даже с тестовым номером) автономная система. То есть, административно, префикс принадлежит одной AS, но анонсирует его в Интернет – совсем другая. Или даже несколько других AS – в зависимости от того, какой оператор из какой точки сети смотрит на BGP. Да, для штатного анонсирования префикса должно быть разрешение от его администратора, сейчас это даже подтверждается в RPKI. Да, конкретная ситуация с приёмом IP-пакетов зависит от фильтров, настроенных оператором. Но это только подчёркивает то, что одно дело – административная принадлежность, другое – BGP и маршрутизация в реальности.

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



Комментарии (11) »

Боты на dxdt.blog

На dxdt.blog продолжают сыпаться десятки тысяч HTTP-хитов в сутки от ИИ-ботов, в том числе, повторные GET-запросы в течение одних суток на одни и те же URL.

Для особо надоедливых ботов я сделал отдельный HTTP-редирект (302), ведущий на специальную страницу, где с кодом статуса 503 возвращается краткая HTML-заглушка. В некоторых случаях это помогает – бот, во-первых, не идёт по редиректу (ну, это предположительно, судя, так сказать, по косвенным признакам), во-вторых – на какое-то время бот, наткнувшийся на редирект в сторону 503, перестаёт сканировать сайт. Но это именно что в некоторых случаях: многие боты так и продолжают тупо прыгать по редиректам, причём, при каждом соседнем запросе – превращая десятки тысяч GET-запросов в десятки тысяч последовательных редиректов. А если такого бота забанить уже на уровне сетевого стека, то он всё равно продолжает лить сетевые запросы. В целом, очень хорошо заметно, как распространение подобных ботов заливает веб – на dxdt.blog трафик ИИ-ботов, по HTTP-хитам с кодом 200, в десятки раз превысил всё остальное.

Ещё наблюдение по этой же теме: я некоторое время назад сделал на сайте специальную ссылку, которая, как я думаю, не должна использоваться при корректной работе с веб-сайтом, но если пройти по URL из неё, то это моментально приводит к блокированию IP-источника уже на уровне сетевого стека (netfilter в ОС, под которой крутится веб-сервер). Ссылку, по понятным причинам, здесь не указываю, но она есть в robots.txt – объявлена, как закрытая (Disallow), что, конечно, может и привлекать запросы. Однако по этой ссылке – совсем мало кто из ботов попадается: видимо, прямое указание в robots.txt – пока работает в сторону “отключения”.



Комментарии (3) »

На днях я писал о том, что сейчас нетрудно сделать веб-сайт без доменного имени, а прямо под IP-адресом (v4), но с доверенным HTTPS для коробочного браузера. В качестве примера – сделал точно такой веб-сайт, с сертификатом от Let’s Encrypt: https://185.39.19.199/ – можно зайти браузером и убедиться, что всё работает. Надо заметить, что TLS-сертификаты для IP-адресов можно было получать в доверенных, хорошо известных УЦ и раньше, это, конечно, не в Let’s Encrypt придумали – но вот только раньше выпуск такого сертификата был сопряжён с существенными дополнительными административными трудностями, а Let’s Encrypt позволяет этих трудностей избежать совсем.

Посмотрим подробнее на сам TLS-сертификат, который сейчас установлен на сервере под указанным выше IP-адресом. Исходный файл сертификата можно получить с сервера – он и так передаётся при каждом TLS-соединении, а здесь – будет текстовая распечатка, полученная при помощи OpenSSL. Так как полная распечатка довольно длинная, а разделю её на части, которые подробно прокомментирую, попутно рассказав, на что это всё влияет.

Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            06:7e:8d:e7:b0:8a:13:8c:23:da:d4:f1:43:e6:de:24:02:f6
        Signature Algorithm: ecdsa-with-SHA384
        Issuer: C = US, O = Let's Encrypt, CN = YE1
        Validity
            Not Before: Apr 26 13:18:14 2026 GMT
            Not After : May  3 05:18:13 2026 GMT
        Subject: 

Здесь указаны самые, наверное, очевидные поля: версия формата (3 – сейчас это типовой вариант); серийный номер; алгоритм подписи – ECDSA, см. ниже; название подписавшего сертификат УЦ (Issuer); период валидности.

Обратите внимание – в сертификате отсутствует поле Subject. Это весьма важный момент, довольно свежий. Сейчас в TLS-сертификатах (для веба) в качестве носителя имён и адресов TLS-узла выступает другое поле – SAN (Subject Alternative Name). Поле Subject может присутствовать в сертификате, но, например, браузеры имена из этого поля игнорируют, если нет соотвествующего имени в SAN. В случае же этого сертификата от Let’s Encrypt, как мы видим, нет самого содержимого поля Subject. Это, в частности, означает, что если в каких-то скриптах (скажем, для мониторинга) это поле используется для определения принадлежности сертификата, то с современными TLS-сертификатами (для веба) скрипт правильно работать не будет. Такие скрипты нужно обновлять – см. ниже.

Вот типичный пример вызова OpenSSL в shell-скрипте, который пытается проверить имя в сертификате по Subject:

openssl x509 -in 185-39-19-199.pem -subject -noout -nameopt multiline \
| awk -F' = ' '/commonName/ {print $2}'

Для старого формата сертификатов (например, как сейчас установлен на dxdt.blog) – этот вызов выведет имя из поля “commonName” в Subject, то есть, для dxdt.blog – напечатает dxdt.blog. Однако в случае с новыми сертификатами – фрагмент не напечатает ничего, но, при этом, обработанный сертификат будет валидным и вполне себе корректным. То есть, полагаться на Subject больше нельзя – нужно заменять вызовы утилит на обработку поля SAN. Это несколько сложнее, но вполне реализуемо.

Для извлечения имён из SAN при помощи OpenSSL (утилита x509) нужно указать опцию -ext subjectAltName. Выдача openssl x509 в этом случае состоит из списка, где тип элемента обозначен префиксом. DNS-имена OpenSSL выводит с префиксом “DNS”, а IP-адреса – “IP address” (это будет полезно для нашего сертификата). Пример:

openssl x509 -in 185-39-19-199.pem -noout -ext subjectAltName

Результат:

X509v3 Subject Alternative Name: critical
    DNS:185.39.19.199.zone, IP Address:185.39.19.199

Скрипт, понятно, усложняется – нужно парсить префиксы полей. Пример скриптового вызова с awk, для извлечения DNS-имени:

openssl x509 -in 185-39-19-199.pem -noout -ext subjectAltName \
| awk 'NR>1{split($0,A,",");for(k in A){split(A[k],B,":"); \
if(B[1]~/DNS/){print B[2]}}}'

Результат:

185.39.19.199.zone

Обратите внимание: 185.39.19.199.zone – это хостнейм, доменное имя, пусть оно и похоже на IP-адрес. Да, в данном сертификате присутствует и DNS-имя, и IP-адрес – это делает сертификат хорошим примером. В принципе, сервер доступен и под доменным адресом 185.39.19.199.zone, но основным мы тут считаем IP-адрес. Для выпуска сертификата на IP-адрес не требуется указание доменного имени. Но если имя нужно включить в сертификат, то это нетрдуно сделать при помощи того же certbot – просто указываем при вызове и доменное имя, и IP-адрес:

certbot certonly --preferred-profile shortlived \
-d 185.39.19.199.zone \
--ip-address 185.39.19.199 \
--webroot --webroot-path /var/www/html/

Вернёмся к распечатке исходного сертификата. Предыдущий блок закончился на пустом Subject. Смотрим дальше:

        Subject Public Key Info:
            Public Key Algorithm: id-ecPublicKey
                Public-Key: (256 bit)
                pub:
                    04:ea:98:84:aa:0e:d5:2b:0f:5a:00:6b:bc:17:df:
                    33:91:86:e5:f8:b6:cb:e8:f0:7b:48:f0:5f:bf:8c:
                    04:57:9e:7f:ee:66:a8:09:7a:31:f3:11:d5:2f:90:
                    67:01:af:04:cc:45:52:56:5d:18:73:bf:1c:d5:6d:
                    f9:f7:44:6e:5d
                ASN1 OID: prime256v1
                NIST CURVE: P-256

Это открытый ключ. В сертификате указан открытый ключ для ECDSA на кривой P-256. Это, опять же, типовой сейчас вариант, ничего необычного.

        X509v3 extensions:
            X509v3 Key Usage: critical
                Digital Signature
            X509v3 Extended Key Usage: 
                TLS Web Server Authentication
            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Authority Key Identifier: 
                BB:20:CA:47:0B:FE:D7:E5:9C:F9:8F:09:2A:A3:8C:37:45:B1:BC:D8
            Authority Information Access: 
                CA Issuers - URI:http://ye1.i.lencr.org/

Далее идут так называемые “расширения” (extensions). Key Usage и Extended Key Usage – обозначают допустимое использование открытого ключа из сертификата. Сейчас, в случае TLS-сертификатов для веба, перечень флагов, указываемых в этих полях Удостоверяющим Центром (УЦ), сильно сократили: здесь есть только Digital Signature (цифровая подпись) в основном поле Key Usage и TLS Web Server Authentication (аутентификация TLS-сервера для веба) – в дополнительном Extended Key Usage. И всё – это, опять же, нововведение: тут нт ни клиентской аутентификации, ни “шифрования ключа” или “ключевого обмена”, ни чего-то ещё подобного.

CA:FALSE в Basic Constraints – ключ из сертификата не может быть использован в качестве доверенного для проверки подписи на других сертификатах (это если строго; простыми словами говорят, что “это не сертификат ключа УЦ”).

Authority Key Identifier – идентификатор ключа для проверки подписи; это, вообще говоря, историческое поле, которое предназначено для “быстрого поиска” ключа проверки подписи на сертификате, но, понятно, без самого ключа не имеет смысла.

Authority Information Access – указание на точки раздачи файлов с информацией об удостоверяющем центре. В данном случае, указана только точка раздачи по HTTP сертификата ключа УЦ – CA Issuers.

Далее идёт поле SAN, с именами и адресами, которое мы упоминали выше:

            X509v3 Subject Alternative Name: critical
                DNS:185.39.19.199.zone, IP Address:185.39.19.199

Указано одно доменное имя (DNS) и один IP-адрес (IP Address). Ещё раз напомню, что могли быть и только IP-адреса, причём, разных версий – v4, v6. Современные барузеры в процессе валидации сопоставляют имена или адреса из поля SAN, не из Subject. Например, при подключении по IP-адресу 185.39.19.199, браузер проверит, что в TLS-сертификате указан именно этот адрес в поле SAN.

Интересен вопрос контекста: что использует браузер – IP-адрес или доменное имя? В сертификате могут быть указаны оба этих артефакта, но браузер при валидации использует тот, который пользователь ввёл при вызове. То есть, если обращение по имени хоста, то сранивается имя хоста, если по IP-адресу напрямую, то сравнивается IP-адрес. Понятно, что почти всякое HTTP-обращение, в стетевом смысле, производится по IP-адресу. Я как-то (https://dxdt.blog/2025/04/15/15391/) писал о том, что, в теории, для случая хостнейма, тоже можно использовать и IP-адреса из сертификата, в качестве дополнительного фактора – совпал и домен, и IP-адрес. Но в современной практике веба это, скорее, излишняя перестарховка, сопряжённая с техническими сложностями, к тому же.

            X509v3 Certificate Policies: 
                Policy: 2.23.140.1.2.1
            X509v3 CRL Distribution Points: 
                Full Name:
                  URI:http://ye1.c.lencr.org/119.crl

Политики (Policies) – тут просто указан идентификатор политики УЦ, в рамках которой проводилась проверка права управления ресурсом (адресом, именем) и выпускался сертификат. Политики – это больше административный момент. Но, например, именно идентификатором политики определяются так называемые EV-сертификаты (Extended Validation), которые сейчас почти что утратили актуальность.

X509v3 CRL Distribution Points – точка раздачи CRL – списка отозванных сертификатов. В данном сертификате есть механизм проверки отзыва – это CRL. В принципе, для короткоживущих сертификатов от механизма отзыва собираются вообще отказаться, но тут адрес CRL все же указан (отчасти, потому что это сертификат для IP-адреса).

Хвост сертификата, с сокращениями:

            CT Precertificate SCTs: 
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : E3:23:8D:F2:8D:A2:88:E0:AA:E0:AC:F0:FA:90:C9:85:
                                F0:B6:BF:F5:D2:A5:27:B0:01:FC:1C:44:58:C4:B6:E8
                    Timestamp : Apr 26 14:16:45.523 2026 GMT
                    Extensions: 00:00:05:00:36:66:ED:17
                    Signature : ecdsa-with-SHA256
[...]
                Signed Certificate Timestamp:
                    Version   : v1 (0x0)
                    Log ID    : D1:6E:A9:A5:68:07:7E:66:35:A0:3F:37:A5:DD:BC:03:
                                A5:3C:41:12:14:D4:88:18:F5:E9:31:B3:23:CB:95:04
                    Timestamp : Apr 26 14:16:45.489 2026 GMT
                    Extensions: none
                    Signature : ecdsa-with-SHA256
[...]
    Signature Algorithm: ecdsa-with-SHA384
    Signature Value:
[...]

CT Precertificate SCTs – это подписанные метки времени, полученные для этого сертификата от операторов логов Certificate Transparency.

Далее – повторное указание на тип подписи в сертификате (ecdsa-with-SHA384). Это тип криптосистемы цифровой подписи, использованной УЦ. Тот же идентификатор уже встречался в начале сертификата – так сложилось исторически: идентификатор указывается в двух местах, хотя точно хватило бы и одного, в конце, где приводится сама подпись – Signature Value.



Комментировать »