Фингерпринтинг по раскладке клавиатуры считывает раскладку через getLayoutMap() — тихий сигнал только для Chromium, намекающий на регион и почти не меняющийся.
Фингерпринтинг по раскладке клавиатуры считывает сигнал, о котором большинство людей никогда не задумывается: физическую раскладку, на которую настроена ваша клавиатура, — она раскрывается через метод getLayoutMap() из Keyboard API. Сайт может, по сути, спросить: «какой символ выдаёт эта физическая клавиша?» — и ответ раскроет вашу раскладку на уровне ОС (QWERTY, AZERTY, QWERTZ, JIS и десятки других) без единого запроса разрешения. В этой статье объясняется, как работает API, почему физическая раскладка выдаёт локаль и регион, и что на самом деле ограничивает её полезность как сигнала слежки.
Ключевые выводы
navigator.keyboard.getLayoutMap()возвращает соответствие между кодами физических клавиш (например,"KeyQ") и символом, который ваша раскладка выдаёт в этой позиции ("q"на QWERTY,"a"на AZERTY).- Физическая раскладка коррелирует с локалью и регионом — AZERTY распространена во Франции, QWERTZ — стандарт для Германии/Австрии/Швейцарии, JIS — только для Японии, — добавляя сигнал, независимый от
navigator.languageили часового пояса. - API реализован только в десктопных браузерах на Chromium (Chrome 69 и новее, Edge, Opera); Firefox и Safari вообще его не предоставляют, а спецификация прямо не рассчитывает на поддержку в мобильных браузерах — поэтому он бесполезен против значительной доли посетителей.
- Он не показывает пользователю никакого диалога с запросом разрешения; единственные ограничения — требование безопасного (HTTPS) контекста и функция Permissions Policy
keyboard-mapсо списком разрешенийselfпо умолчанию, то есть переключатель в руках самого сайта, что совершенно не то же самое, что согласие пользователя. - Поскольку изменение системной раскладки клавиатуры — осознанное и редкое действие, это значение необычно стабильно между сессиями по сравнению с такими сигналами, как разрешение экрана или размер окна.
Что такое фингерпринтинг по раскладке клавиатуры?
Фингерпринтинг по раскладке клавиатуры — это практика определения того, какую физическую раскладку клавиш использует операционная система прямо сейчас, с помощью Keyboard API, и включения этого значения в идентификатор устройства или браузера. Это всего один небольшой вызов API, но он добавляет сигнал, который не покрывают другие техники фингерпринтинга: большинство наборов для фингерпринтинга считывают рендеринг-оборудование (canvas, WebGL), установленное ПО (шрифты) или заявленные настройки (navigator.language, часовой пояс) — ни одно из этого напрямую не отражает, как ваша физическая клавиатура подключена к ОС.
В отличие от фингерпринтинга по шрифтам или canvas, эта техника не основана на выводе через различия рендеринга. getLayoutMap() — специально созданный для этой цели API, который возвращает информацию о раскладке напрямую, что и делает его интересным для отдельного разбора.
Внутри getLayoutMap(): что он возвращает
getLayoutMap() возвращает Promise, который разрешается в KeyboardLayoutMap — доступный только для чтения объект, похожий на Map. Его ключи — это коды физических клавиш из стандартного набора значений code, которые определяют клавишу по её позиции на клавиатуре независимо от того, что напечатано на клавише ("KeyQ" — это всегда клавиша сразу справа от Tab, независимо от раскладки). Его значения — это символ, который ваша текущая раскладка выдаёт в этой позиции.
// Считываем символ, который каждая физическая клавиша выдаёт при текущей раскладке
async function getKeyboardLayoutSignal() {
if (!navigator.keyboard?.getLayoutMap) return null; // Firefox, Safari: не поддерживается
const layoutMap = await navigator.keyboard.getLayoutMap();
const probeCodes = ['KeyQ', 'KeyW', 'KeyA', 'KeyY', 'KeyZ', 'Semicolon', 'BracketLeft'];
// На QWERTY: KeyQ -> "q". На AZERTY: KeyQ -> "a", KeyW -> "z", KeyA -> "q".
return probeCodes.map((code) => layoutMap.get(code) ?? null).join(',');
}
Различие между кодом (физической позицией) и клавишей (произведённым символом) — это именно то, что делает данный сигнал пригодным для фингерпринтинга: два посетителя с идентичным оборудованием и идентичной версией браузера могут вернуть разные строки на один и тот же запрос, просто потому что у них различается настройка раскладки клавиатуры на уровне ОС. Опроса нескольких кодов, которые сильнее всего различаются между QWERTY, AZERTY и QWERTZ (буквенные клавиши), достаточно, чтобы очень небольшим количеством кода отнести посетителя к конкретному семейству раскладок.
Почему физическая раскладка выдаёт локаль и регион
Раскладки клавиатуры распределены неравномерно — они плотно группируются по странам и языковым сообществам:
- QWERTY доминирует в США, Великобритании и большинстве англоязычных регионов (с британским вариантом, в котором отличается несколько клавиш пунктуации).
- AZERTY — раскладка по умолчанию во Франции и Бельгии.
- QWERTZ — стандарт в Германии, Австрии и Швейцарии.
- JIS-раскладки специфичны для Японии; ЙЦУКЕН — для России и других стран с кириллическим письмом.
Именно эта кластеризация делает сигнал ценным для трекера: это косвенный показатель региона, независимый от геолокации по IP, и независимый от заголовка Accept-Language или navigator.language, которые заботящийся о приватности пользователь мог уже переопределить. Посетитель, заявляющий IP из США и navigator.language на английском, но при этом сообщающий раскладку AZERTY, — это несоответствие, которое стоит пометить: та же логика, которую наш чек-лист согласованности отпечатка применяет к несоответствиям GPU/ОС, применима здесь к несоответствиям языка и раскладки. Сама по себе раскладка — грубый, низкоэнтропийный сигнал: в мире всего несколько десятков распространённых раскладок, — но в сочетании с другими атрибутами она сужает круг, в котором может затеряться посетитель.
Поддержка браузерами и модель разрешений
Практическая применимость этой техники ограничена тем, где API вообще существует:
| Браузер | Поддержка getLayoutMap() | Диалог для пользователя |
|---|---|---|
| Chrome / Edge / Opera для десктопа (Chromium) | Да (Chrome 69+) | Нет |
| Chromium на мобильных | Обычно отсутствует либо возвращает пустую карту | Не применимо |
| Firefox | Не реализован | Не применимо |
| Safari | Не реализован | Не применимо |
Стоит отметить три вещи. Во-первых, этот сигнал доступен исключительно в Chromium: скрипт слежки, полагающийся на него, в Firefox и Safari молча получит undefined, поэтому он в принципе может отслеживать лишь часть трафика веба.
Во-вторых, на телефонах охват ещё уже. Спецификация WICG keyboard-map прямо говорит: поскольку у мобильных устройств обычно нет физической клавиатуры, этот API «как правило, не будет присутствовать или поддерживаться на мобильных устройствах», а мобильная платформа, которая всё же его реализует, вправе вернуть карту раскладки без единой записи. Для аудитории, которая заходит в основном с телефонов, это отсекает большую часть людей, которых техника могла бы разложить по группам, — и во многом поэтому она остаётся вспомогательным сигналом, а не основным.
В-третьих, там, где API поддерживается, нет диалога согласия, подобного тем, что запускают доступ к камере, микрофону или геолокации. API требует лишь безопасного (HTTPS) контекста и разрешения от функции Permissions Policy keyboard-map, чей список разрешений по умолчанию — self. В это значение стоит вчитаться: скрипт первой стороны на самой странице вызывает метод свободно, а кросс-доменный <iframe> получает SecurityError, если встраивающая страница явно не разрешила ему это через allow="keyboard-map". То есть граница проводится оператором сайта между ним самим и его встроенным контентом, а не запрашивается у посетителя. С точки зрения пользователя вызов происходит бесшумно: ни иконки, ни диалога, ни способа заметить, что это вообще произошло. Для сравнения, связанный метод keyboard.lock() ограничен полноэкранными сессиями и играми — это другая функция с другой моделью угроз, а не барьер для getLayoutMap(). API до сих пор числится экспериментальной, не-Baseline функцией, что и объясняет, почему поддержка в разных браузерах так и не расширилась.
Стабильность: почему этот сигнал почти не меняется
Большинство атрибутов отпечатка со временем дрейфуют: вы подключаете второй монитор — и меняется разрешение экрана; вы устанавливаете шрифт — и растёт список шрифтов; обновление браузера немного меняет строку User-Agent. Раскладка клавиатуры на этом фоне необычно статична. Изменение раскладки на уровне ОС требует открыть системные настройки и осознанно её переключить — подавляющее большинство пользователей никогда этого не делает, поскольку раскладка привязана к физической клавиатуре, которой они пользуются каждый день. Именно эта стабильность делает сигнал привлекательным как вспомогательный: даже если скрипт проверяет его лишь изредка, значение, зафиксированное месяц назад, почти наверняка остаётся верным и сегодня — в отличие от canvas-шума, который приватный браузер может менять от сессии к сессии.
Как это вписывается в общую картину
Фингерпринтинг по раскладке клавиатуры — второстепенный вклад по сравнению с canvas, WebGL или шрифтами, но он иллюстрирует закономерность, которую стоит уметь распознавать: браузеры продолжают открывать узкие, целевые API (медиаустройства, голоса синтеза речи, сетевая информация), каждый из которых понемногу выдаёт данные об устройстве или локали, без собственного диалога разрешения. Ни один из них не решающий сам по себе; вместе они накапливаются. Наш полный гайд по фингерпринтингу браузера рассказывает, как эти сигналы сочетаются, а фингерпринтинг по шрифтам — его близкий родственник: обе техники нацелены на Chromium и другие браузеры без единого видимого запроса и обе сильнее всего работают как один из многих входных сигналов, а не как самостоятельный идентификатор.
Как снизить риск
- Используйте браузер, который не реализует этот API. Firefox и Safari просто не предоставляют
getLayoutMap(), так что посетители в этих браузерах не подвержены именно этой технике независимо от любых других настроек. - В Chromium сократите то, до чего скрипты могут дотянуться без спроса. Расширение, которое блокирует сторонние трекеры ещё до их выполнения, убирает само место вызова — но выбирайте избирательно, поскольку расширение с широким доступом само по себе становится вектором слежки; прежде чем что-то устанавливать, см. риски приватности от браузерных расширений. Если вы не только посещаете сайты, но и ведёте свой, заголовок
Permissions-Policy: keyboard-map=()отключает эту функцию для вашей страницы и всего, что в неё встроено. - Не полагайтесь только на сокрытие языковых настроек. Если подделывать
navigator.languageили регион, показываемый IP, оставляя при этом реальную раскладку клавиатуры без изменений, вы создаёте именно то несоответствие, которое этот сигнал хорошо умеет ловить — согласованность всех ваших сигналов важнее сокрытия любого одного из них. - Помните об ограничениях. Как и фингерпринтинг по шрифтам и canvas, это сигнал на уровне рендеринга/API, а не сохранённые данные — приватный режим/инкогнито его не меняет, потому что там просто нечего очищать.
Часто задаваемые вопросы
Требует ли фингерпринтинг по раскладке клавиатуры каких-либо разрешений?
Нет. getLayoutMap() требует лишь безопасного (HTTPS) контекста и функции Permissions Policy keyboard-map — которая по умолчанию разрешена для собственного источника страницы и может быть отключена заголовком самого сайта. Ни то, ни другое не показывает посетителю диалог согласия. Он по замыслу бесшумен.
Какие браузеры можно отслеживать таким способом?
Только десктопные браузеры на Chromium — Chrome (начиная с версии 69), Edge, Opera и другие, построенные на том же движке. Firefox и Safari не реализовали getLayoutMap(), поэтому эта техника вообще не применима к их пользователям, а на мобильных устройствах спецификация поддержки и не ожидает.
Моя раскладка клавиатуры — это то же самое, что язык ввода?
Не обязательно. Раскладка — это системная настройка, привязанная к физической клавиатуре; вы можете печатать на определённом языке, используя раскладку, отличную от «родной» для страны этого языка, хотя большинство людей так не делает. Именно поэтому раскладка полезна как дополнительный сигнал, а не дублирует navigator.language.
Можно ли идентифицировать меня только по этому сигналу?
Нет — в мире всего несколько десятков распространённых раскладок, поэтому сам по себе это низкоэнтропийный сигнал. Он становится значимым только в сочетании с другими атрибутами отпечатка или когда противоречит другим заявленным вами сигналам локали.
Как проверить, что раскрывает мой браузер?
Запустите проверку отпечатка BrowserInsight, чтобы увидеть полный набор сигналов, которые раскрывает ваш браузер, включая то, насколько заявленные вами значения согласуются друг с другом.
Заключение
Фингерпринтинг по раскладке клавиатуры — это небольшой, тихий вызов API, который превращает системную настройку, о которой почти никто не задумывается, в коррелирующий с локалью сигнал, не требующий разрешения, — и он необычно стабилен, поскольку изменить его требует осознанного усилия. Он ограничен десктопными браузерами на Chromium и сам по себе несёт низкую энтропию, но это наглядный пример того, как узкие, целевые API браузера продолжают накапливаться: каждый понемногу утекает, ни один не спрашивает — а вместе они сужают круг, в котором может затеряться посетитель.
Хотите увидеть весь набор, а не отдельный сигнал? Запустите бесплатную проверку отпечатка — она считывает атрибуты, которые ваш браузер раздаёт наружу, и показывает, где они согласуются друг с другом, а где нет.
Рекомендуем прочитать:


