Afina

Скачати додаток

AppleWindows
UA

Як браузер визначає встановлені шрифти та формує font fingerprint

Робот показує абстрактні гліфи у вікні браузера для перевірки локальних шрифтів

Font fingerprint означає набір ознак локальних шрифтів, за якими сайт може відрізнити одне браузерне середовище або пристрій від іншого. Сайти використовують його для перевірки верстки й доповнення browser fingerprint, але результат залежить від дозволів і захисту браузера.

Як у почерку, однаковий текст має різну форму й ширину. Розберемося, як це перевірити.

Чи можуть сайти визначати встановлені шрифти

Так, але переважно непрямо. Без явного дозволу сайт не може читати вашу папку зі шрифтами й не отримує перелік файлів із диска. Він порівнює, як браузер малює однаковий рядок різними гарнітурами, і за різницею ширини, рамки тексту чи пікселів робить висновок, що конкретний шрифт імовірно доступний. Це евристика, тому можливі хибні результати: встановлений шрифт із метриками, близькими до fallback, може лишитися непоміченим, а псевдоніми назв та інші особливості добору шрифтів ускладнюють інтерпретацію.

Прямий перелік існує лише в настільному Chromium через queryLocalFonts(), і він потребує явного дозволу користувача та тимчасової активації (transient user activation), наприклад кліку. Firefox і Safari цього API не мають, а WebKit додатково приховує від сайтів шрифти, які користувач встановив самостійно. Тому відповідь залежить від браузера: в одному випадку сайт бачить лише непрямі ознаки, в іншому після дозволу отримує повний доступний йому список.

Що саме бачить сайт під час перевірки локальних шрифтів

Без дозволу сторінка не отримує C:\Windows\Fonts чи каталог Font Book. Вона бачить ознаки даних шрифтів за виглядом тексту.

Джерелом буває ОС, локальна інсталяція або @font-face. Загальні сімейства serif, sans-serif, monospace, cursive, fantasy і system-ui не вказують файл. cursive означає рукописний стиль, fantasy - декоративний; гарнітуру обирають ОС і браузер.

Це font matching. За відсутності кандидата браузер бере fallback, або запасний шрифт. Гліф - намальована форма символу.

Браузер може:

  • вибирати шрифт за CSS-назвою
  • отримувати метрики: ширину, висоту й положення літер
  • завантажувати вебшрифт
  • повертати локальні шрифти, відкриті цьому браузеру й сайту, через queryLocalFonts() після дозволу

Готовність тексту ще не доводить, що Arial є на диску.

Як сайти визначають шрифт без запиту на дозвіл

Скрипт перебирає назви й порівнює розміри або пікселі тексту. Canvas fingerprinting працює схоже, але геометрія та пікселі дають різні сигнали.

Як працює порівняння з fallback

Браузер малює рядок fallback і кандидатом, потім порівнює:

  1. Візьми широкі й вузькі символи, наприклад mmmmmmmmmmlliWW@@.
  2. Виміряй їх у monospace, serif і sans-serif.
  3. Постав потрібну назву перед кожним fallback.
  4. Порівняй ширину й bounding box, тобто рамку навколо тексту.
  5. Познач шрифт як імовірно доступний, якщо змінилася хоча б одна пара.

Але однакові метрики в різних гарнітур можуть призводити до хибнонегативних результатів. Кілька fallback, розмірів і перевірка висоти зменшують кількість помилок, але не відкривають весь каталог.

Схема методу вимірювання ширини fallback-тексту для визначення шрифтів

Цей код робить ось що: невидимо малює той самий рядок різними шрифтами та порівнює його розміри. Для розуміння принципу запускати код не потрібно.

const ctx = document.createElement("canvas").getContext("2d");
const sample = "mmmmmmmmmmlliWW@@";
const fallbacks = ["monospace", "serif", "sans-serif"];

function metrics(fontStack) {
  ctx.font = `72px ${fontStack}`;
  const m = ctx.measureText(sample);
  return [m.width, m.actualBoundingBoxAscent, m.actualBoundingBoxDescent].join("|");
}

function fontLooksAvailable(family) {
  return fallbacks.some((fallback) => {
    const baseline = metrics(fallback);
    const candidate = metrics(`"${family}", ${fallback}`);
    return candidate !== baseline;
  });
}

console.log(fontLooksAvailable("Arial"));

Canvas API дає браузеру полотно для малювання, а measureText() повертає розмір напису. Сайт тихо перевіряє так сотні назв.

Чим font metrics відрізняються від піксельного Canvas hash

Метрики показують розмір. Canvas fingerprint читає намальовані пікселі через getImageData() або toDataURL() і створює hash.

Пікселі залежать від згладжування, графічної системи, файла й hinting, тобто підлаштування літер під сітку екрана. Однакова ширина не гарантує однакового зображення. Браузер може змінювати Canvas readback, тобто читання готового зображення, і користувач нічого не помітить. А от обмеження видимості шрифтів помітне: сторінка може взяти fallback замість встановленої гарнітури.

Чи можна перевіряти локальний шрифт через CSS local()

src: local() шукає накреслення за повною назвою або PostScript name, наприклад HelveticaNeueLTPro-Roman. Без збігу браузер переходить до наступного джерела.

Коли веброзробник хоче підключити шрифт, установлений на комп'ютері користувача, він додає таке CSS-правило безпосередньо до файлу стилів сайту з розширенням .css. У цьому прикладі браузер спочатку шукає Helvetica Neue на пристрої, а якщо не знаходить, завантажує запасний файл із сайту.

@font-face {
  font-family: "ProbeFont";
  src:
    local("Helvetica Neue"),
    local("HelveticaNeue"),
    url("fallback.woff2") format("woff2");
}

Через ризик fingerprinting WebKit приховує користувацькі шрифти, а Firefox робить це в посилених режимах захисту.

Чому document.fonts.check() не доводить, що шрифт встановлено

document.fonts.check() перевіряє показ без очікування, не файл на комп'ютері. Це допомагає уникнути font swap, помітної заміни fallback вебшрифтом.

Цей код робить ось що: питає браузер, чи готовий текст Arial до показу без очікування. Значення true не доводить, що Arial встановлено локально.

const available = document.fonts.check('16px "Arial"');
console.log(available);

Вигадана назва теж повертає true, якщо браузер одразу бере fallback. Це означає «чекати не потрібно», не «файл існує».

Для оголошеного через @font-face вебшрифту перевірку запускають після завантаження шрифтів.

Цей код робить ось що: чекає, поки сторінка завершить роботу зі шрифтами, а потім перевіряє, чи можна показати конкретний зразок без раптової заміни гарнітури.

Якщо під час самостійного тестування консоль показує помилку paused in the debugger, виконання сторінки призупинено. Зверни увагу на жовту плашку вгорі екрана браузера й натисни синю кнопку Play (Resume script execution), щоб зняти сторінку з паузи, а потім запусти код ще раз.

const fontSpec = '16px "MyWebFont"';
const sample = "BESbswy";

await document.fonts.ready;
const readyWithoutSwap = document.fonts.check(fontSpec, sample);
console.log({ readyWithoutSwap });

Додай потрібні символи: кирилицю, латиницю, китайські ієрогліфи або emoji. Інакше перевіряться інші гліфи через fallback.

Коли варто використовувати queryLocalFonts()

window.queryLocalFonts() повертає вебредакторам сімейство, повну назву, PostScript name і стиль. Потрібні дозвіл і transient user activation, короткочасна активація кліком чи іншою дією. Фоновий запит неможливий.

Цей код робить ось що: після вставлення в Console чекає першого кліку по самій вебсторінці, просить доступ до локальних шрифтів і виводить дозволені назви. Окрема кнопка на сайті для цього не потрібна.

// Код чекає кліку по всій сторінці
document.body.addEventListener("click", async () => {
  if (!("queryLocalFonts" in window)) {
    console.log("Local Font Access API не підтримується");
    return;
  }

  try {
    const fonts = await window.queryLocalFonts();
    for (const font of fonts) {
      console.log(font.family, font.fullName, font.postscriptName, font.style);
    }
    console.log(`Успішно знайдено шрифтів: ${fonts.length}`);
  } catch (error) {
    console.error(error.name, error.message);
  }
}, { once: true }); // Код виконається лише на перший клік

console.log("Код успішно завантажено! Тепер просто клікни лівою кнопкою миші будь-де на самій вебсторінці (не в консолі), щоб побачити список шрифтів.");

Як перевірити код самостійно:

  1. Скопіюй увесь код із блока вище, встав його у вкладку Console в DevTools і натисни Enter.
  2. Переконайся, що в консолі з'явилося повідомлення «Код успішно завантажено! Тепер просто клікни...».
  3. Клікни мишкою по порожньому місцю на самій вебсторінці або збоку від тексту, а не у вікні DevTools.
  4. Натисни «Дозволити» / Allow у запиті дозволу браузера.
  5. Повернися до вкладки Console: там миттєво з'явиться повний список локальних шрифтів, доступних цьому браузеру, і підсумкове повідомлення з їх кількістю.

Запит потребує HTTPS; сайт або браузер може його блокувати. Результат не обов'язково охоплює весь каталог. У настільному Chromium перевір підтримку через 'queryLocalFonts' in window. Firefox, Safari й мобільні Chromium API не мають. Можливості:

  • queryLocalFonts({ postscriptNames: [...] }) запитує конкретні внутрішні назви
  • FontData.blob() після дозволу повертає SFNT-дані, вміст контейнера .ttf/.otf, а не лише назву

Без дозволу доступні лише непрямі ознаки; з Local Font Access API - метадані шрифтів, а через FontData.blob() ще й самі SFNT-дані шрифту.

Чим відрізняється визначення шрифтів у Chromium, Firefox і Safari

Chromium пропонує API з дозволом, Firefox посилює захист у спеціальних режимах, а WebKit приховує встановлені користувачем шрифти.

ПоверхняChromium desktopFirefoxSafari і WebKit
fallback metrics і Canvasдоступні без окремого захистузахист може приховати локальні шрифти чи змінити Canvasдоступні для дозволеного набору; користувацькі шрифти приховано
document.fonts.check()готовність, не інсталяціята сама логіката сама логіка
queryLocalFonts()настільні версії, після дозволунемаєнемає
режим приватностіIncognito не змінює всі сигналиPrivate Browsing і ETP Strict посилюють захисткористувацькі шрифти приховано за замовчуванням, не лише в приватному режимі; Private Browsing додатково додає шум у читання 2D Canvas і WebGL

Захист Firefox від fingerprinting може обмежувати видимість нестандартних шрифтів, додавати шум під час зчитування зображень Canvas і блокувати відомі fingerprinting-скрипти, залежно від увімкненого режиму захисту.

Схема того, як встановлені шрифти формують відбиток браузера та ідентифікацію відвідувача

WebKit обмежує додані користувачем, але дозволяє системні й вебшрифти. Тому Chrome і Safari на Mac різняться.

Як дізнатися, який шрифт браузер реально відрендерив

DevTools показує шрифт фрагмента й fallback.

БраузерДе шукатиЩо показує
Chrome, Afina та інші Chromium-браузериElements → Computed → Rendered Fontsфактично використані шрифти та кількість гліфів
FirefoxInspector → Fonts → Fonts usedшрифти елемента та сторінки
SafariElements → Fonts sidebarосновний шрифт, накреслення та варіації

font-family: Inter, Arial, sans-serif задає чергу кандидатів. Rendered Fonts показує фактичний вибір.

Щоб знайти Rendered Fonts у Chrome або відкритому профілі Afina:

  1. Відкрий DevTools через F12 або Ctrl+Shift+I у Windows, Cmd+Opt+I на Mac. Або клікни текст правою кнопкою та вибери «Переглянути код» / Inspect.
  2. Відкрий Elements, зазвичай першу вкладку.
  3. Клікни HTML-елемент тексту. Інший спосіб: натисни стрілку з квадратиком ліворуч угорі, наведи її на текст і клікни.
  4. Відкрий праворуч Computed біля Styles. Якщо панелі немає, розшир DevTools.
  5. Прокрути Computed донизу й розгорни Rendered Fonts. Там видно фактичний шрифт і кількість його гліфів.

Один рядок може поєднувати Inter для латиниці, системний emoji-шрифт і fallback для відсутньої кириличної літери. У кроці 3 вибирай проблемний фрагмент.

Панель Computed у Chrome DevTools з секцією Rendered Fonts для обраного елемента

Чому назва файлу не дорівнює CSS font-family

Один файл має кілька назв:

File:            HelveticaNeueLTPro-Roman.otf
Family:          Helvetica Neue LT Pro
Full name:       Helvetica Neue LT Pro Roman
PostScript name: HelveticaNeueLTPro-Roman

font-family використовує сімейство, src: local() - повну назву або PostScript name, а queryLocalFonts({ postscriptNames }) - точний PostScript name. Назва файла .otf чи .ttf може з ними не збігатися.

Чому браузер не бачить щойно встановлений шрифт

Основні причини: браузер не перезапущено, назва неправильна або працює захист від fingerprinting.

СимптомІмовірна причинаЩо зробити
ОС бачить шрифт, сайт нібраузер відкрито до інсталяціїзакрий усі вікна й процеси, запусти знову
в іншому акаунті шрифту немаєCurrent User, не All Usersперевір цей акаунт або встанови для всіх за наявності прав і ліцензії
regular є, bold ніbold відсутній або імітуєтьсяперевір менеджер і Rendered Fonts
назва файла не працюєfilename не збігається з family/PostScript nameперевір внутрішні назви
гарнітури немає у програмахформат непідтримуванийзнайди .ttf/.otf; для вебу конвертуй ліцензований шрифт у WOFF2, не обмежуйся простим перейменуванням розширення файлу
помилки або зникненняфайл пошкодженийперевір менеджером і перевстанови з надійного джерела
Chrome бачить, Safari ніWebKit приховує користувацькі шрифтипідключи ліцензований вебшрифт через @font-face або fallback
Firefox Strict показує меншепосилений захиствимкни його лише для діагностики й увімкни назад
відрізняються окремі символинемає потрібних гліфіввибери цей текст у Rendered Fonts

Перевірка у Windows:

  1. Натисни Win+I й відкрий Персоналізація → Шрифти.
  2. Знайди назву й відкрий картку з накресленнями.

Альтернативний шлях:

  1. Відкрий Провідник через Win+E.
  2. Введи C:\Windows\Fonts в адресному рядку й натисни Enter.
  3. Скористайся пошуком праворуч угорі.

На macOS використовуй системний застосунок Font Book:

  1. Натисни Command+Space, введи Font Book і відкрий застосунок.
  2. Увімкни View → Show Sidebar і вибери колекцію.
  3. Знайди гарнітуру, накреслення, символи та внутрішні дані.
  4. Активуй приглушений шрифт через Edit → Activate.
  5. Перевір файл через File → Validate Selection: зелений колір означає успіх, жовтий - попередження, червоний - помилку.
  6. Усунь дублікати через File → Resolve Duplicates. Current User чи All Users указано в Font Book → Settings → Installation.

У Linux fc-list показує список, а fc-match "Arial" - підставлений файл. Потім перевір реальний вибір у Rendered Fonts.

Як локальні шрифти перетворюються на font fingerprint

Скрипт поєднує карту шрифтів із Canvas, WebGL, екраном та іншими ознаками. Чекери браузерних відбитків мають різні списки й алгоритми.

Важлива рідкість комбінації: рідкісний шрифт може додати значно більше ідентифікуючої ентропії, ніж звичайні системні шрифти.

Сторінка результатів тесту font fingerprinting зі списком знайдених шрифтів та показником унікальності

Adobe, офісні й CAD-програми додають характерні сімейства. Вони підказують можливий софт, але не доводять професію чи особу.

Fonts fingerprint допомагає впізнати браузер, коли стабільний набір узгоджується з іншими сигналами.

Як правильно порівнювати результати й зменшити fingerprinting

Перевірка в BrowserLeaks:

  1. Введи browserleaks.com/fonts в адресному рядку потрібного профілю.
  2. Зачекай 5–15 секунд до заповнення Font Metrics і Unicode Glyphs, не перемикаючи вкладку.
  3. Запиши кількість шрифтів зі звіту (report) та загальний відбиток. На скриншоті залиш назву тесту й ці значення.
  4. Закрий профіль, запусти інший профіль Afina й повтори тест.
  5. Порівняй дані. Різні сайти несумісні.

Щоб порівняння було чесним:

  1. Використовуй той самий checker; запиши браузер, ОС і захист.
  2. Не змінюй масштаб сторінки чи екрана.
  3. Дочекайся вебшрифтів через @font-face; це не локальні шрифти.
  4. Перезапусти профіль і тест. Важлива стабільність.

Чому кількість знайдених шрифтів змінюється

Кількість може змінитися без ручного встановлення шрифту:

  • ОС і програми додають, оновлюють або видаляють гарнітури
  • мовні пакети додають кирилицю, арабське письмо, CJK та інші знаки
  • Adobe Fonts та інші хмарні сервіси активують шрифти до виходу або вимкнення синхронізації
  • корпоративні політики змінюють шрифти робочих пристроїв
  • дозволи браузера: local-fonts, приватний режим і захист змінюють видимий набір
  • словники тестів: один сайт перевіряє 100 назв, інший 500

Повтори тест на тому самому сайті й у профілі, потім перевір ОС, програми та дозволи.

Як обмежити перевірку локальних шрифтів

Зменшити обсяг даних можна так:

  • без потреби відхиляй local-fonts через «Заблокувати» / Block; виняток - інструмент, якому потрібен список
  • увімкни штатний захист Firefox, WebKit або іншого браузера
  • розділяй cookies, cache та інші дані між профілями; вони не видаляють системні шрифти, тому конфігурація має бути стабільною
  • блокуй JavaScript лише в крайньому разі: зникнуть меню, форми, відео, авторизація й онлайн-тести

Підміна шрифтів або вимкнення JavaScript можуть зламати дизайн, символи й читабельність. Змінюй захист поступово.

Інкогніто ізолює cookies та історію, але не обов'язково змінює метрики шрифтів.

Незвичний набір шрифтів, який не узгоджується із заявленою ОС чи іншими сигналами відбитка, робить загальний fingerprint помітнішим.

Міні-тест: чи бачить браузер конкретний шрифт

Такий тест можна розмістити прямо у статті, щоб читачеві не довелося відкривати Console. Користувач вводить назву гарнітури, а сторінка порівнює розмір однакового тексту зі шрифтом-кандидатом і запасним шрифтом.

Структура інтерактивного блока для верстальника:

  1. Поле «Назва шрифту». Однорядкове поле з прикладом Arial або Roboto і короткою підказкою вводити саме family name, а не назву .ttf чи .otf файлу.
  2. Кнопка «Перевірити». Після натискання запускає вимірювання одного тестового рядка в кількох fallback-сімействах.
  3. Блок «Шрифт-кандидат». Показує тестовий рядок і його ширину в пікселях після додавання введеної назви перед fallback.
  4. Блок «Fallback-текст». Показує той самий рядок, розмір і ширину без шрифту-кандидата.
  5. Обережний результат. Якщо розміри відрізняються, показати «Імовірно доступний». Якщо різниці немає, показати «Не вдалося підтвердити». Не використовувати категоричні статуси «Знайдено» або «Не знайдено».

Під результатом потрібне коротке пояснення: тест працює як евристика, тобто робить припущення за різницею розмірів. Він не сканує диск і не доводить, що конкретний файл шрифту встановлено в системі.

Як контролювати шрифтовий сигнал в ізольованих профілях

Сайт зіставляє шрифти з Canvas, WebGL, cookies і мережею. Профіль має давати узгоджений, стабільний результат.

Для антидетект-профілів узгодженість важливіша за просте зменшення кількості видимих шрифтів. Профіль, який заявляє Windows, повинен показувати шрифтову поведінку, правдоподібну саме для Windows, і той самий профіль повинен давати стабільний результат між запусками. Рідкісний, але внутрішньо несуперечливий набір шрифтів виглядає менш підозріло, ніж рандомізований набір, який суперечить заявленій ОС, Canvas чи іншим сигналам.

Потенційні невідповідності узгодженості відбитка включають:

  • Windows у User-Agent і набір шрифтів, характерний лише для macOS
  • macOS-відбиток і специфічні для Windows гарнітури
  • набір шрифтів, що змінюється між двома запусками одного профілю
  • Canvas-рендеринг, який розходиться з виміряними метриками шрифтів

Afina ізолює fingerprint, proxy, cookies і cache в Chromium-профілі для керування fingerprint. Списку локальних шрифтів у налаштуваннях немає: сигнал перевіряють після запуску.

Як перевірити налаштування відбитка та результат у конкретному профілі Afina:

  1. Відкрий Afina й ліворуч вибери «Акаунти».
  2. Натисни ⋮ → Змінити для профілю. Для нового вибери «Додати акаунт», потім «Новий акаунт».
  3. Перевір ОС, User-Agent, CPU, пам'ять, Canvas, WebGL, Аудіо й Rects у «Основні» → «Браузерний відбиток». Шрифтову видимість оцінюй у складі повного відбитка, а не як окреме налаштування.
  4. Натисни «Скасувати» без змін або «Зберегти» після них. «Згенерувати новий відбиток» змінює профіль.
  5. Познач профіль в «Акаунтах», натисни «Запуск» і дочекайся браузера.
  6. Введи browserleaks.com/fonts в адресному рядку, зачекай 5–15 секунд і запиши кількість шрифтів зі звіту (report) та загальний відбиток.
  7. Перезапусти тест; повтори в іншому профілі Afina й порівняй.
  8. Відкрий Canvas- і WebGL-тести сервісу в кожному профілі. Оцінюй стабільність та узгодженість усіх сигналів, не один «зелений» показник.

Висновок

Більшість методів визначення шрифтів залишаються евристичними: сайт порівнює метрики й пікселі та робить імовірнісний висновок, а не читає перелік файлів на диску. Local Font Access API дає точніші дані, проте суворо контролюється дозволом користувача й тимчасовою активацією і доступний лише в настільному Chromium. Обмеження зайвих дозволів на кшталт local-fonts, штатний захист браузера та ізольовані профілі допомагають зменшити обсяг доступних сайту даних, хоча жоден із цих кроків не працює сам собою. Для надійного захисту від відстеження визначальною є загальна узгодженість усього відбитка браузера, а не лише кількість видимих шрифтів: один font hash не доводить ані унікальності, ані анонімності.

Скачати

FAQ — Часті запитання

Чи може сайт бачити всі шрифти, встановлені на комп'ютері?

Без дозволу сайт не бачить увесь каталог шрифтів. Після дозволу queryLocalFonts() повертає доступний браузеру список.

Як сайт визначає, чи встановлено конкретний шрифт?

Сайт порівнює розмір тексту з fallback або пікселі Canvas. Така непряма перевірка може помилятися.

Чому document.fonts.check() повертає true для неіснуючого шрифту?

document.fonts.check() може повернути true, бо браузер одразу підставляє fallback і не чекає завантаження.

Які браузери підтримують queryLocalFonts()?

queryLocalFonts() після дозволу працює в настільних Chromium, але не у Firefox, Safari чи мобільних Chromium.

Чи може сайт завантажити мій локальний файл шрифту?

Без дозволу сайт не читає локальний файл. Після дозволу FontData.blob() може надати дані шрифту.

Чи захищає режим інкогніто від font fingerprinting?

Інкогніто не дає повного захисту від font fingerprinting. Режим ізолює сесію, але може зберігати метрики та інші сигнали.

Як дізнатися, який шрифт браузер реально використав?

Фактичний шрифт видно в секції Rendered Fonts. У DevTools вибери текст і відкрий Elements → Computed → Rendered Fonts.

Як зменшити font fingerprinting?

Щоб зменшити font fingerprinting, відхиляй зайві дозволи й увімкни захист браузера. Звіряй шрифти з Canvas та WebGL.

Чи можна визначити пристрій або операційну систему за набором шрифтів?

Набір шрифтів може підказати ОС чи встановлені програми. Цей сигнал потрібно звіряти з Canvas, WebGL, мовою та іншими даними.

Чим локальний шрифт відрізняється від вебшрифту?

Локальний шрифт установлено в ОС. Вебшрифт сайт завантажує через @font-face.

Схожі терміни

Читати далі:Антидетект браузер — анонімність профілів | Afina Browser
Владислав Шестаков

Привіт! Я Владислав Шестаков — фахівець із аналізу даних та автоматизації в Afina. Зосереджений на веб-автоматизації, підтримці та розвитку продукту. Маю досвід у криптовалюті, машинному навчанні та створенні власних ботів і інструментів автоматизації. Поєдную технічну експертизу з постійним саморозвитком та інтеграцією сучасних технологій, щоб робити роботу з Web3 ефективною та зрозумілою

Поділитися