WebSocket і локальні порти: як антифрод виявляє ознаки середовища

WebSocket локальні порти означають канал, через який сайт може непрямо оцінити сервіси на localhost за часом відповіді. Його використовують, щоб помітити відкриті налагоджувальні порти, локальні агенти, proxy-клієнти або сліди автоматизації.
Для команд, які працюють з кількома профілями, ця тема стоїть поруч із перевіркою WebRTC-витоків і UDP-поведінки. Зовнішній IP і проксі можуть виглядати акуратно, але браузер усе одно залишається процесом на локальній машині. Якщо сторінка бачить непрямі ознаки цього середовища, цифровий відбиток стає ширшим за Canvas, WebGL і User-Agent.
Саме тому WebSocket timing attack варто розглядати як частину браузерного fingerprinting. Він не читає файли, не отримує список процесів і не показує назву програми. Але він може дати сигнал: порт швидко відмовив, відповів із затримкою або взагалі завис до timeout. У поєднанні з Canvas, WebGL і video fingerprinting та поведінковими метриками такий сигнал допомагає антифроду оцінювати середовище сесії.
Окремо стоїть порт 9222, який часто асоціюють із Chrome DevTools Protocol. Якщо в браузері активовано віддалене керування через CDP, а сайт фіксує нетипову часову різницю на цьому порту, це може стати додатковим сигналом середовища. Для розуміння суміжних витоків корисно тримати поруч матеріал про CDP-витоки Puppeteer, бо обидві теми стосуються не зовнішнього IP, а того, як автоматизація проявляється всередині браузерного середовища.
Чому вебсторінка може звертатися до локальної адреси
Вебсторінка може створити WebSocket-з'єднання не тільки до віддаленого сервера, а й до адреси на кшталт 127.0.0.1 або localhost. Це не означає, що сайт автоматично читає локальні дані. Суть у спробі встановити з'єднання і виміряти час до браузерної події помилки, який може непрямо залежати від мережевого стану локального порту.
WebSocket був створений для постійного двостороннього зв'язку: чати, біржові графіки, live-статуси, ігри в браузері. На старті браузер робить TCP-з'єднання, надсилає HTTP Upgrade і чекає, чи сервер погодиться перейти в WebSocket-протокол. Якщо адресою є localhost, трафік не виходить у зовнішню мережу. Він іде в loopback-інтерфейс тієї самої операційної системи.
Проблема в тому, що навіть невдала спроба дає побічну інформацію. Сторінка не повинна бачити відповідь MySQL, SSH або локального проксі. І за нормальної моделі безпеки вона її не бачить. Але JavaScript може фіксувати різницю в часі до події помилки. На неї можуть впливати швидка відмова ОС, встановлення TCP-з'єднання з подальшою невдачею WebSocket Upgrade або довший timeout.
Це не класичне сканування портів у стилі nmap. Браузерний скрипт не має сирого доступу до TCP-пакетів, не бачить SYN/ACK напряму і не отримує банер сервісу. Він працює грубіше: пробує кілька портів, фіксує час до події onerror і порівнює результат із базовим значенням.
Для антифрод-системи локальний таймінг набуває значення в поєднанні з іншими ознаками. Якщо в сесії одночасно видно підозрілий User-Agent, нетиповий WebGL renderer, нестабільний IP і таймінг, схожий на відкритий CDP-порт, сукупність сигналів може вплинути на оцінку ризику.
Як час відповіді допомагає оцінити стан порту
Часова атака WebSocket спирається на статистичні відмінності в часі помилки, які за певних умов можуть відповідати закритому, відкритому або відфільтрованому firewall порту. Сайт не читає локальний сервіс, а таймінг не дає гарантованої класифікації стану порту.
Типовий сценарій виглядає просто. Скрипт бере високоточний таймер, запускає new WebSocket("ws://127.0.0.1:9222"), чекає на помилку і рахує різницю. Далі він повторює спробу для кількох портів і порівнює їх із контрольним портом, який майже напевно закритий.
Умовний алгоритм перевірки такий:
- виберіть контрольний високий порт, який не використовується локальними сервісами
- виміряйте середній час помилки для цього контрольного порту
- спробуйте WebSocket-з'єднання з портами, які мають сенс для ризик-моделі
- порівняйте затримку кожного порту з базовим значенням
- відкиньте одиничні викиди, які могли з'явитися через навантаження процесора або garbage collection
- передайте не сирий висновок, а скоринговий сигнал із рівнем впевненості
Цифри не варто читати як універсальний закон. На localhost закритий порт часто дає дуже швидку відмову, відкритий порт може відповідати помітно довше через TCP handshake і невдалий WebSocket Upgrade, а filtered-порт може чекати до системного timeout. Але точні мілісекунди залежать від ОС, браузера, навантаження процесора, політик таймера і того, що саме слухає порт.
| Стан порту | Що відбувається на рівні TCP | Що бачить скрипт | Чому це корисно антифроду |
|---|---|---|---|
| закритий | ОС швидко повертає RST | коротка затримка до onerror | базова лінія нормальної відмови |
| відкритий | handshake проходить, але WebSocket Upgrade ламається | більша затримка до помилки | можливий локальний сервіс або агент |
| filtered | firewall може відкидати пакет без швидкої відповіді | можлива довша затримка або timeout | потенційна ознака фільтрації або нетипового правила |
| нестабільний | результат плаває між спробами | шум у вимірах | сигнал низької впевненості |
Після таблиці легко зробити неправильний висновок: якщо порт відкритий, користувач винен. Насправді ні. Локальні порти відкривають легальні програми: IDE, Docker, VPN-клієнти, менеджери паролів, криптогаманці, корпоративні агенти безпеки. Технічний сигнал стає антифрод-ризиком лише в контексті всієї сесії.

Антифрод-моделі можуть не покладатися на один поріг спрацювання. Вони калібрують час на поточній машині, повторюють спроби, дивляться на розкид значень і зіставляють локальні ознаки з браузерним відбитком. Тут починається зона оцінки, а не прямого доказу.
Що обмежують браузери та операційні системи
Браузери обмежують доступ вебсторінки до локальних ресурсів кількома різними механізмами. Same-Origin Policy і CORS насамперед регулюють доступ до відповідей звичайних вебзапитів, Secure Context визначає доступність окремих можливостей, а Private Network Access додає перевірки для звернень до приватних мереж. Ці механізми не слід вважати однаковим захистом від WebSocket-таймінгів: час до браузерної події помилки за певних умов може залишатися побічним каналом.
Це важлива межа. Якщо сайт спробує прочитати відповідь локального HTTP-сервера через fetch, браузер має заблокувати доступ до тіла відповіді без потрібних CORS-заголовків. WebSocket працює інакше: сервер може перевіряти Origin. Але сам факт успішного або невдалого шляху до помилки все одно виникає.
Операційна система теж не завжди усуває такий побічний канал. Loopback-трафік не виходить за межі пристрою, а поведінка firewall щодо нього залежить від ОС і конфігурації. Правила DROP і REJECT також можуть створювати різні часові характеристики.
Коли Ви налаштовуєте захист, різниця між цими діями практична:
REJECTзазвичай швидко повертає відмову, але конкретний таймінг залежить від ОС, firewall і мережевої конфігураціїDROPможе відкидати пакет без швидкої відповіді та спричиняти довший timeout- повне блокування localhost може ламати легальні локальні агенти
- список дозволених сервісів зменшує шум, але потребує підтримки
- окреме середовище профілю краще ізолює локальні сервіси від браузерної сесії
Якщо у Вас кілька робочих ролей на одній машині, не варто відкривати все в одному звичайному браузері і сподіватися, що проксі вирішить локальні витоки. Проксі змінює зовнішній маршрут, але не прибирає локальний Docker daemon, CDP endpoint або корпоративний агент, який слухає порт на loopback.
Private Network Access частково закриває класичні сценарії доступу з публічних сайтів до приватних мережевих ресурсів. Але PNA не є універсальною відповіддю на timing side-channel. Якщо браузеру треба спробувати з'єднання, щоб потім відхилити його політикою, сама різниця часу може залишитися корисною для скорингу.

Для практичної безпеки це означає одне: не варто покладатися на один шар. Браузерна політика зменшує доступ до даних, firewall контролює реакцію ОС, а ізоляція середовища прибирає зайві локальні сервіси з поля зору робочої сесії.
Як такі сигнали можуть входити до антифроду
Антифрод може використовувати локальні WebSocket-таймінги як один із сигналів середовища. Конкретне використання залежить від платформи, її ризик-моделі та правил.
Сигнал локального порту потенційно може бути корисним у трьох ситуаціях:
- система перевіряє ознаки автоматизації через CDP, Playwright, Puppeteer або Selenium
- оцінює нетипове серверне середовище, де на localhost відкриті бази даних, SSH, панелі керування або локальні проксі
- зіставляє нібито незалежні профілі за повторюваним набором локальних ознак
Тут WebSocket timing attack перетинається з темою headless browser detection. Headless-режим може мати помітні ознаки у WebDriver, canvas-параметрах або поведінці API. Локальний порт додає ще один шар: не те, як браузер малює сторінку, а те, що поруч із браузером працює на машині.
Умовний приклад того, як такий сигнал теоретично може виглядати в скоринговій системі:
| Сигнал | Низький ризик | Вищий ризик | Коментар |
|---|---|---|---|
9222 або інший CDP-порт | порт закритий або недоступний | у теоретичній моделі є затримка, схожа на відкритий endpoint | потребує зіставлення з іншими сигналами автоматизації |
| порти локального проксі | можуть бути очікуваними в корпоративному сценарії | у теоретичній моделі повторюються в багатьох акаунтах | потенційно можуть бути одним із кластерних сигналів |
| порти SSH або баз даних | можуть бути нетиповими для звичайного споживчого середовища | у теоретичній моделі повторюються між сесіями | можуть бути ознакою серверного або робочого середовища |
| filtered-таймінги | поодинокі й нестабільні | системні для багатьох портів | може видати агресивне firewall-правило |
| однаковий набір локальних портів | випадковий збіг | повторюється в десятках профілів | потенційний сигнал для кластерного аналізу |
Якщо кілька профілів із різними IP, cookies і fingerprint мають однаковий набір локальних портів, система оцінки ризику потенційно може врахувати повторюваний патерн як ознаку спільної інфраструктури.
Важливо враховувати не тільки браузер, а й мережевий маршрут. Якщо профілі працюють через різні проксі, але всі вони запускаються на одній машині з однаковими локальними сервісами, проксі не розділяє цей шар. Для QUIC, UDP і SOCKS5 це окрема тема, яку варто зіставити з матеріалом про UDP через SOCKS5 і маршрутизацію QUIC.

Ми не стверджуємо, що кожна платформа виконує локальне сканування портів. Такий механізм технічно можливий і його можна перевірити в контрольованому середовищі, тому його варто враховувати в чеклисті безпеки для команд, які працюють із чутливими акаунтами.
Як перевірити локальне середовище й зменшити витік даних
Перевірка локального середовища починається з інвентаризації портів, а не з випадкового встановлення розширень. Спочатку потрібно зрозуміти, що саме слухає localhost, які сервіси потрібні для роботи і які з них можуть створювати нетиповий патерн для браузерної сесії.
На macOS і Linux базову картину дають lsof -iTCP -sTCP:LISTEN -n -P або ss -ltnp. На Windows можна почати з netstat -ano і зіставити PID із процесами в Task Manager або PowerShell. Далі список треба не просто зберегти, а розділити на нормальні, службові й ризикові порти.
Практичний порядок аудиту такий:
- перевірте список портів, що прослуховуються, перед запуском робочого браузера
- закрийте IDE, локальні сервери, Docker-контейнери й debug-сесії, якщо вони не потрібні для завдання
- переконайтеся, що CDP-порт не відкритий назовні без реальної потреби
- обмежте доступ до непотрібних локальних сервісів за допомогою firewall і залиште доступними лише необхідні для роботи з’єднання
- протестуйте один і той самий профіль у звичайному браузері та в ізольованому середовищі
- повторіть вимірювання кілька разів, щоб відокремити стабільний сигнал від шуму
- задокументуйте, які локальні агенти дозволені в командному SOP
У робочих процесах із багатьма акаунтами та сама логіка переходить у кластерний ризик. Один профіль із відкритим локальним портом може бути випадковістю. П'ятдесят профілів із однаковим набором локальних портів можуть вказувати на спільну інфраструктуру. Саме тут доречно згадати Sybil-детекцію і кластерний аналіз, бо системи оцінки ризику можуть враховувати не один окремий сигнал, а повторювану структуру ознак.
Що робити на практиці, якщо Ви керуєте командною інфраструктурою:
- розділяйте робочі ролі за окремими профілями й середовищами
- не запускайте automation-debugging у тому самому середовищі, де входите в важливі акаунти
- використовуйте список дозволених локальних агентів, які справді потрібні
- відрізняйте блокування від швидкої відмови, бо для таймінгу це різні сигнали
- фіксуйте зміни в SOP, щоб команда не відкривала випадкові порти перед робочою зміною
- перевіряйте не лише IP і fingerprint, а й локальний мережевий контур
Afina доречна в такому процесі як інфраструктура для ізольованих браузерних профілів, керування fingerprint-параметрами, проксі та командними доступами. Ізоляція профілів дає змогу розділяти cookies, сесії, налаштування проксі та робочі ролі, але не замінює аудит локальної ОС, firewall і сервісів на localhost. Матеріал надано виключно в ознайомчих та освітніх цілях.
Для командного SOP зручно тримати окремий чеклист: які локальні сервіси дозволені, які порти не мають бути відкриті перед запуском профілю, хто відповідає за оновлення правил firewall і де зберігаються результати тестів. Така документація допомагає відстежувати зміни середовища та аналізувати причини додаткових перевірок ризику для окремих профілів.
СкачатиFAQ — Часті запитання
Що таке WebSocket timing attack?
WebSocket timing attack дає змогу оцінити стан локального порту за часом помилки під час спроби з'єднання. Скрипт не читає локальні дані, але порівнює затримки між закритими, відкритими та фільтрованими портами.
Чи може сайт сканувати localhost через браузер?
Сайт може спробувати звернутися до localhost через браузерні API, зокрема WebSocket. Браузер обмежує доступ до відповіді, але сам час помилки може залишатися побічним сигналом.
Чому порт 9222 вважається ризиковим?
Порт 9222 часто пов'язують із Chrome DevTools Protocol і керуванням браузером для автоматизації. Сам по собі відкритий порт не доводить порушення, але в антифрод-скорингу він може підсилити інші automation-сигнали.
Чи захищає CORS від WebSocket port scanning?
CORS обмежує читання відповідей у звичайних вебзапитах, але не прибирає всі таймінгові побічні канали. Для WebSocket важливі також TCP-handshake, помилка Upgrade і час до onerror.
Чи вирішує Private Network Access проблему локальних портів?
Private Network Access додає обмеження для частини звернень із публічних сайтів до приватних мережевих ресурсів. Його поведінка залежить від браузера, типу запиту та актуальної реалізації, тому PNA не варто вважати універсальним захистом від усіх таймінгових побічних каналів.
Як перевірити відкриті локальні порти?
На macOS і Linux використовуйте lsof або ss, а на Windows почніть із netstat -ano. Після цього зіставте порти з процесами й закрийте сервіси, які не потрібні для робочої сесії.
Чи достатньо проксі для захисту від localhost-сигналів?
Ні, проксі змінює зовнішній мережевий маршрут, але не прибирає локальні сервіси на машині. Для localhost-сигналів важливі ізоляція середовища, firewall і контроль debug-портів.
Чи можна повністю заборонити браузеру доступ до localhost?
Можливість повністю обмежити доступ залежить від браузера, операційної системи та мережевої політики. Жорстке блокування може порушити роботу легальних локальних агентів, тому в керованому середовищі доцільно окремо визначати дозволені сервіси та правила для небажаних з'єднань.
