TCP fingerprinting: почему бот не может притвориться Windows

Бот отправляет идеальный User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36.... Cookies на месте, JavaScript выполняется, Canvas-отпечаток совпадает с эталонным. Казалось бы — обычный пользователь Windows. Но один SYN-пакет выдаёт правду: это Linux-сервер в дата-центре. Технология, которая делает это возможным, называется TCP fingerprinting — пассивное определение операционной системы по параметрам TCP-стека. В этой статье мы разберём, как она работает, почему её нельзя обмануть программными средствами и как она применяется для защиты рекламного бюджета от ботов.

Что происходит до HTTP: TCP-рукопожатие

Прежде чем браузер отправит HTTP-запрос, прежде чем сработает любой JavaScript-детектор, происходит нечто фундаментальное — TCP-рукопожатие (three-way handshake). Это три пакета, которые устанавливают соединение между клиентом и сервером:

  1. SYN — клиент отправляет серверу запрос на соединение.
  2. SYN-ACK — сервер подтверждает и отправляет свои параметры.
  3. ACK — клиент подтверждает, соединение установлено.
  4. Ключевой момент: первый SYN-пакет формируется ядром операционной системы, а не браузером и не приложением. Браузер вызывает системный вызов connect(), а всё остальное — выбор размера окна, установку TTL, порядок TCP-опций — делает сетевой стек ядра. У каждой ОС эти значения по умолчанию различаются, и именно это лежит в основе TCP fingerprinting.

    Это принципиально отличает TCP fingerprinting от всех прикладных методов детекции. JavaScript можно подменить, User-Agent — подделать, Canvas-отпечаток — эмулировать. Но параметры SYN-пакета задаёт ядро ОС, и без модификации ядра изменить их невозможно.

    Анатомия TCP-отпечатка: пять ключевых параметров

    TCP fingerprinting опирается на комбинацию нескольких параметров SYN-пакета. По отдельности каждый из них мало что значит, но вместе они создают уникальную подпись операционной системы.

    Window Size (размер окна)

    Начальный размер TCP-окна — это количество байт, которое клиент готов принять до получения подтверждения. Каждая ОС использует своё значение по умолчанию:

    • Windows 10/11: 64240 байт
    • Linux (ядро 5.x–6.x): 29200 байт
    • macOS Sonoma: 65535 байт

    Это значение жёстко задано в коде сетевого стека. Windows использует 64240 уже много лет — это значение оптимизировано под типичные сетевые условия и не менялось с Windows Vista. Linux использует 29200, что соответствует 20 сегментам по 1460 байт. macOS исторически выставляет максимальное 16-битное значение — 65535.

    MSS (Maximum Segment Size)

    MSS определяет максимальный размер полезных данных в одном TCP-сегменте. Для Ethernet-подключений стандартное значение — 1460 байт (MTU 1500 минус 20 байт IP-заголовка и 20 байт TCP-заголовка). Это значение одинаково для большинства ОС при прямом Ethernet-подключении, но меняется при использовании VPN или PPPoE, что тоже даёт полезную информацию.

    TTL (Time to Live)

    TTL — это «время жизни» пакета, счётчик, который уменьшается на единицу при прохождении каждого маршрутизатора. Начальное значение TTL задаётся ОС:

    • Windows: 128
    • Linux: 64
    • macOS: 64

    Даже если пакет прошёл через несколько маршрутизаторов и TTL уменьшился, исходное значение легко восстановить — достаточно округлить до ближайшей степени двойки. Если мы получили TTL=119, значит, исходное значение было 128 (Windows), а пакет прошёл 9 маршрутизаторов. Если TTL=52, то исходное значение — 64 (Linux или macOS), и пакет прошёл 12 хопов.

    DF (Don’t Fragment) флаг

    Флаг DF в IP-заголовке указывает маршрутизаторам не фрагментировать пакет. Современные реализации TCP почти всегда устанавливают DF=1 в SYN-пакетах, используя механизм Path MTU Discovery. Однако некоторые старые или встроенные системы этого не делают, что позволяет отличить их от десктопных ОС.

    TCP Options и их порядок

    Это самый мощный параметр TCP fingerprinting. TCP-опции — это дополнительные поля в заголовке TCP-сегмента, которые согласовывают расширенные возможности соединения. Критически важен не просто набор опций, а их точный порядок.

    Windows 10/11 отправляет опции в следующем порядке:

    
    MSS(1460), NOP, Window Scale(8), NOP, NOP, SACK Permitted
    

    Linux (ядро 5.x–6.x):

    
    MSS(1460), SACK Permitted, Timestamps, NOP, Window Scale(7)
    

    macOS Sonoma:

    
    MSS(1460), NOP, Window Scale(6), NOP, NOP, Timestamps, SACK Permitted, EOL
    

    Обратите внимание: Windows не отправляет опцию Timestamps в SYN-пакете — это одно из самых надёжных различий между Windows и Unix-подобными системами. Linux использует Window Scale(7), macOS — Window Scale(6), Windows — Window Scale(8). Порядок NOP-заполнителей тоже различается.

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

    Сводная таблица TCP-отпечатков

    Параметр Windows 10/11 Ubuntu 22.04 (Linux 5.15+) macOS Sonoma Android 13+
    Window Size 64240 29200 65535 65535
    TTL 128 64 64 64
    MSS 1460 1460 1460 1460
    DF flag 1 1 1 1
    Window Scale 8 7 6 6
    SACK Permitted Да Да Да Да
    Timestamps Нет Да Да Да
    Порядок опций MSS, NOP, WS, NOP, NOP, SACK MSS, SACK, TS, NOP, WS MSS, NOP, WS, NOP, NOP, TS, SACK, EOL MSS, NOP, WS, NOP, NOP, TS, SACK, EOL

    Эта таблица — не теоретическая модель. Это реальные данные, собранные с продакшн-серверов. Каждая строка представляет десятки тысяч проанализированных SYN-пакетов.

    Обратите внимание на Android и macOS: их отпечатки очень похожи, что логично — Android использует ядро Linux, а macOS основан на Darwin/BSD. Однако Window Size и Window Scale позволяют различить их.

    Пример из реальных данных

    Рассмотрим конкретный случай. На сервер приходит HTTP-запрос с заголовками:

    
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
                AppleWebKit/537.36 (KHTML, like Gecko)
                Chrome/122.0.0.0 Safari/537.36
    

    Все JavaScript-проверки пройдены: navigator.platform возвращает Win32, Canvas-отпечаток совпадает с реальным Chrome на Windows, WebGL рендерер указывает на NVIDIA GeForce. По прикладным признакам — идеальный пользователь.

    Но TCP-уровень показывает другую картину:

    
    window: 29200
    ttl: 64 (исходный)
    options: [MSS(1460), SACK, Timestamps, NOP, WS(7)]
    

    Window Size 29200, TTL 64, Timestamps в опциях, Window Scale(7) — это безошибочно Linux. Порядок опций совпадает с ядром Linux 5.x. Никакой Windows так не выглядит на уровне TCP.

    Вердикт: бот, запущенный на Linux-сервере, использует headless-браузер с подменённым User-Agent. TCP fingerprinting разоблачает его до того, как выполнится первая строка JavaScript.

    Теперь сравним с легитимным пользователем:

    
    window: 64240
    ttl: 128 (исходный)
    options: [MSS(1460), NOP, WS(8), NOP, NOP, SACK]
    

    Window Size 64240, TTL 128, отсутствие Timestamps, характерный порядок NOP-заполнителей — это Windows 10 или 11. User-Agent и TCP-отпечаток совпадают. Пользователь подлинный.

    Почему бот не может подделать TCP-отпечаток

    Это центральный вопрос, и ответ кроется в архитектуре операционных систем.

    Когда бот запускается на Linux-сервере (а подавляющее большинство ботов работают именно на Linux — это дешевле, проще автоматизировать и масштабировать), его TCP-стек формируется ядром Linux. Приложение — будь то headless Chrome, Puppeteer, Playwright или кастомный HTTP-клиент — не контролирует параметры SYN-пакета. Оно вызывает connect(), а ядро заполняет все TCP-параметры по своим внутренним настройкам.

    Чтобы бот на Linux отправил SYN-пакет, идентичный Windows, нужно одно из трёх:

    1. Модифицировать ядро Linux. Пересобрать ядро с изменёнными значениями tcp_init_sock(), tcp_options_write() и десятками других функций сетевого стека. Это требует глубокой экспертизы в ядре Linux и делает систему нестабильной.
      1. Использовать raw sockets. Формировать TCP-пакеты вручную, минуя стандартный сетевой стек. Это означает реализацию собственного TCP-стека с нуля — управление соединениями, ретрансмиссиями, контролем потока. Практически нереализуемо для полноценного HTTP-клиента.
        1. Запустить реальную Windows. Использовать виртуальную машину или VDS с Windows. Это работает, но стоит значительно дороже Linux-серверов, сложнее автоматизируется и резко снижает рентабельность ботнета.
        2. На практике менее 0,1% ботов модифицируют TCP-стек. Это слишком сложно, слишком дорого и слишком нестабильно для массовых операций. Экономика кликфрода не позволяет тратить ресурсы на такой уровень маскировки.

          p0f и история пассивного OS fingerprinting

          Идея определения ОС по TCP-параметрам не нова. Проект p0f, созданный Михалом Залевски (Michal Zalewski) в начале 2000-х, стал первым широко известным инструментом пассивного TCP fingerprinting. В отличие от активных сканеров вроде Nmap, которые отправляют специальные пакеты для определения ОС, p0f работает полностью пассивно — только анализирует проходящий трафик.

          p0f поддерживает базу сигнатур, описывающих TCP-параметры различных операционных систем. Инструмент анализирует SYN-пакеты входящих соединений и сопоставляет их с базой. Точность определения ОС достигает 95–98% для основных платформ.

          Однако у классического p0f есть ограничения. Он работает в пользовательском пространстве (userspace), что создаёт накладные расходы на копирование пакетов из ядра. При высокой нагрузке — десятки тысяч соединений в секунду — это становится узким местом. Кроме того, база сигнатур p0f обновляется нерегулярно и может отставать от новых версий ОС.

          Другие инструменты — такие как Nmap OS detection — работают активно: они отправляют специально сформированные пакеты целевому хосту и анализируют ответы. Это точнее, но неприменимо для антифрод-сценариев: мы не можем отправлять зондирующие пакеты каждому посетителю сайта. Нужен именно пассивный подход — анализ того, что клиент отправляет сам.

          Современный подход — использование eBPF (extended Berkeley Packet Filter). eBPF позволяет запустить программу анализа непосредственно внутри ядра Linux, без копирования пакетов в пользовательское пространство. Это даёт нулевые накладные расходы и возможность обрабатывать сотни тысяч соединений в секунду. Каждый SYN-пакет анализируется прямо в ядре, а результат — готовый TCP-отпечаток — передаётся в систему принятия решений. При этом eBPF-программы проходят верификацию в ядре, что гарантирует их безопасность и стабильность.

          Почему VPN и прокси не помогают ботам

          Распространённое заблуждение: если бот использует VPN или резидентный прокси, его невозможно обнаружить. Для IP-репутационных систем это действительно проблема — резидентный прокси предоставляет IP-адрес реального домашнего провайдера. Но TCP fingerprinting работает на другом уровне.

          VPN и прокси меняют IP-адрес и маршрут пакета, но не модифицируют TCP-параметры. SYN-пакет формируется на машине бота до того, как попадает в VPN-туннель. VPN-сервер инкапсулирует пакет в свой туннель и передаёт дальше, но внутренний TCP-заголовок остаётся нетронутым.

          Это означает: бот на Linux-сервере, работающий через цепочку из пяти резидентных прокси, всё равно отправит SYN-пакет с Window Size 29200, TTL 64 и характерным Linux-порядком TCP-опций. IP-адрес будет московского провайдера, а TCP-стек — серверного Linux. Именно поэтому TCP fingerprinting является единственным методом детекции, который не теряет эффективности при использовании ботами премиальных резидентных прокси-сервисов.

          Единственное, что может измениться — MSS и TTL. Некоторые VPN-протоколы уменьшают MSS из-за дополнительных заголовков туннелирования (например, MSS 1380 вместо 1460 при использовании WireGuard). TTL уменьшается при прохождении маршрутизаторов, но исходное значение восстанавливается элементарно. Все остальные параметры — Window Size, порядок опций, Window Scale, наличие Timestamps — проходят сквозь VPN без изменений.

          TCP fingerprinting в обнаружении рекламного фрода

          Для антифрод-систем TCP fingerprinting — это фундаментальный слой детекции. Вот как он работает в связке с другими сигналами:

          Сценарий 1: несовпадение User-Agent и TCP-отпечатка

          User-Agent заявляет Windows Chrome, но TCP-отпечаток показывает Linux. Это безусловный индикатор бота. Реальный пользователь Windows физически не может отправить SYN-пакет с Linux-параметрами. Ложные срабатывания в этом сценарии практически исключены.

          Сценарий 2: серверный TCP-профиль

          TCP-отпечаток показывает Linux с параметрами, характерными для серверных ядер (специфичные значения TCP Window Scale, нестандартные MSS). Даже если User-Agent совпадает с заявленной ОС, серверный профиль TCP-стека — сильный сигнал автоматизации.

          Сценарий 3: кластерный анализ

          Группа визитов с разных IP-адресов, но с идентичным TCP-отпечатком. Если 50 «разных пользователей» из разных городов отправляют SYN-пакеты с абсолютно одинаковыми параметрами (одинаковый Window Size, одинаковый TTL, одинаковый порядок опций) — это бот-ферма. Реальные пользователи используют разные ОС, разные версии, разные сетевые конфигурации.

          Точность и надёжность

          TCP fingerprinting не существует в вакууме. Максимальная эффективность достигается при комбинации с другими слоями: TLS fingerprinting (JA3/JA4), HTTP/2-отпечатками, поведенческим анализом. Но именно TCP-слой является наиболее фундаментальным и сложным для подделки — он работает на уровне ядра ОС, до любого пользовательского приложения.

          Почему это важно для вашего бюджета

          Если вы управляете рекламными кампаниями в Яндекс.Директ, Google Ads или программатик-платформах, TCP fingerprinting напрямую влияет на ваш ROI. Стандартные средства защиты от скликивания работают на уровне приложения: анализируют cookies, JavaScript-метрики, поведение мыши. Современные боты научились обходить все эти проверки.

          TCP fingerprinting невозможно обойти без переписывания ядра операционной системы или отказа от дешёвых Linux-серверов. Это создаёт экономический барьер, который делает кликфрод нерентабельным: стоимость маскировки TCP-стека превышает доход от фальшивых кликов.

          По нашим данным, внедрение TCP fingerprinting в связке с TLS-анализом позволяет обнаружить до 70% бот-трафика, который проходит мимо стандартных JavaScript-детекторов и IP-блоклистов. Для рекламодателей с бюджетом от 500 000 рублей в месяц это означает экономию в десятки и сотни тысяч рублей ежемесячно — деньги, которые иначе уходили бы на клики, за которыми не стоит ни один живой человек.

          Заключение

          TCP fingerprinting — это не экспериментальная технология, а зрелый, проверенный метод с двадцатилетней историей. Каждый SYN-пакет несёт в себе подпись операционной системы, которую невозможно подделать на прикладном уровне. Window Size, TTL, порядок TCP-опций — все эти параметры задаются ядром ОС и остаются неизменными вне зависимости от браузера, VPN или прокси.

          Для антифрод-систем это означает надёжный, фундаментальный слой детекции, который работает до HTTP, до JavaScript, до любых прикладных проверок. Бот может идеально имитировать браузер — но не может имитировать операционную систему на уровне TCP-стека.

Scroll to Top