Пустите трафик через Амстердам — и Google поздоровается с вами по-голландски. Почти каждый пользователь VPN натыкался на эту досадную мелочь и списывал её на причуды VPN. Но это не причуда. Это утечка, которой посвящена статья, — просто запущенная в обратную сторону.
Запрос противоречил сам себе. Пакеты пришли с голландского IP-адреса; заголовки сообщили, какие языки вы читаете на самом деле: Accept-Language: en-US,en;q=0.9. Для выбора языка интерфейса Google верит IP. Антифрод-скрипт на странице оплаты проводит то же самое сравнение, но в обратную сторону: он проверяет, вяжутся ли языки с IP, и подшивает ответ к вашему риск-скорингу. Виджет на этой странице прогоняет ровно эту проверку на вашем браузере — прямо сейчас.
Accept-Language: заголовок в каждом запросе
Когда браузер просит у сервера что угодно — страницу, картинку, шрифт, — он прикладывает HTTP-заголовок Accept-Language. Заголовок существует для того, чтобы серверы могли выбрать язык, который вы понимаете, а собирается он из списка языков в настройках браузера — того самого, который при установке был заполнен из локали вашей ОС. Нотация q=0.9 ранжирует список: этот браузер предпочитает американский английский, а просто английский идёт следом почти вплотную. Полная грамматика описана на странице Accept-Language в MDN.
Этот заголовок есть уже в самом первом запросе, который вы отправляете. Не после загрузки какого-то скрипта, не после установки cookie. Сервер читает его тем же взглядом, что и IP-адрес, с которого пришёл пакет:
198.51.100.7 база геолокации Амстердам, NLGET /checkout HTTP/1.1 Host: shop.example User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) ... Accept-Language: en-US,en;q=0.9 ◄ список языков самого браузера
JavaScript получает ту же информацию через navigator.language, а полный список — через navigator.languages, безо всякого запроса разрешения. Обратите внимание на разницу с часами: чтобы узнать ваш часовой пояс, скрипту нужно сначала запуститься; язык же прибывает раньше, чем у страницы вообще появляются скрипты.
Почему VPN не меняет язык браузера
VPN не делает с этим ровным счётом ничего. Туннель перевозит ваши пакеты, но не переводит их. Что браузер написал, то и доставляется — включая заголовок, сообщающий: «мой пользователь читает по-английски, а не по-голландски». И переписать его даже не обсуждается: на любом HTTPS-сайте заголовок едет внутри TLS-сессии между браузером и сайтом, а её VPN вскрыть не может.
Что несовпадение доказывает, а что — нет
Язык — сигнал мягкий, мягче часового пояса. Английский для операционной системы — почти заводская настройка, поэтому en-US с амстердамского IP сам по себе никого не настораживает. Бельгия живёт на трёх официальных языках, Швейцария — на четырёх. Экспаты и удалёнщики совершенно законно читают не на том языке, что их соседи. Любая серьёзная система детекта всё это знает, поэтому языковое несовпадение лишь чуть сдвигает скоринг — и не более того.
Но у этого сигнала есть остриё. Браузер, предпочитающий pt-BR, за голландским выходным IP не так двусмыслен, как английский: он говорит, что человек за клавиатурой читает на бразильском португальском, а в Нидерландах в избытке IP-адресов, но совсем немного домов, где португальский — первый язык. Сложите это с IP дата-центра и часами, всё ещё выставленными на America/Sao_Paulo, — и пакеты, заявляющие «Амстердам», спор проиграли:
nl-NL, nl+ амстердамский IPсогласуется Пара рассказывает одну историю. Начислять баллы не за что.en-US, en+ амстердамский IPнеоднозначно Английские браузеры встречаются повсюду. Сам по себе сигнал слабый, но он идёт в зачёт, когда наваливаются остальные.pt-BR, pt+ амстердамский IPнесовпадение Браузер указывает на Бразилию, а пакеты утверждают, что вы в Нидерландах. Вот теперь вы интересны.- заголовок:
nl-NL+ JavaScript:pt-BRобнаружен спуфинг Браузер спорит сам с собой, а до такого не доводит почти ничего, кроме сознательного вмешательства.
Есть и вторая, более тихая цена. Точный состав вашего списка — какие языки, в каком порядке, с какими значениями q — это материал для отпечатка. Исследование Panopticlick от EFF намерило в Accept-заголовках около шести бит идентифицирующей информации — на этом и держится fingerprinting по Accept-Language: en-US,en;q=0.9 прячется в толпе, а nl-BE,fr-BE;q=0.9,en;q=0.8,de;q=0.7 — считай, подпись. Для сравнения: ваш список шрифтов выдаёт вдвое с лишним больше бит — но его скрипту ещё надо измерить, а этот заголовок сам приходит с каждым запросом.
Производители браузеров это знают. Safari ровно по этой причине отправляет только один, главный язык, у инженеров Chrome есть предложение урезать заголовок до одного языка, а Brave намеренно размывает свой ответ от сайта к сайту. Правда, с несовпадением всё это не помогает: тот единственный язык, что переживает урезание, — по-прежнему ваш.
Почему с VPN Google говорит не на том языке
Вернёмся к голландскому Google. Если браузеры вежливо объявляют свой язык в каждом запросе, почему сайты игнорируют его, стоит вам подключиться через VPN? Потому что IP-геолокации они доверяют больше — и доверяли задолго до того, как у вас появился VPN. Google сказал это прямым текстом в анонсе 2017 года, когда перестал привязывать страновые версии к доменам вроде google.nl и начал отдавать то, что следует из определённой им локации. Заголовок формулирует предпочтение; IP считается фактом. Та же иерархия, что раздражает вас на главной странице Google, работает и в антифрод-системе, когда ваш заголовок расходится с вашим IP: побеждает IP, а заголовок разжалуют из предпочтения в улику.
Если ваша настоящая проблема — само это раздражение, лекарство лежит в настройках аккаунта, а не в настройках VPN: языковые предпочтения залогиненного пользователя обычно перекрывают угадывание по IP и у Google, и у большинства крупных сайтов. А вот у утечки странички с настройками нет, потому что утечка — это сам заголовок.
Ловушка половинчатого спуфинга, дубль два
Читатели статьи о часовом поясе эту ловушку уже видели. Здесь она той же формы, и попасться в неё ещё легче: язык существует в двух местах — в заголовке Accept-Language в сети и в navigator.languages в JavaScript-движке. В нормальном браузере это две проекции одной и той же настройки, и они согласны всегда. Инструменты, подделывающие одну, как правило, забывают о другой.
Спуфинг-расширения по большей части переопределяют сторону JavaScript — до неё расширению проще всего дотянуться, — а заголовок тем временем продолжает говорить каждому серверу правду. Прокси, переписывающие заголовки, делают ровно наоборот и оставляют navigator.languages докладывать ваш настоящий список каждому скрипту, который спросит. В обоих случаях браузер начинает спорить сам с собой, и это противоречие для системы детекта ценнее исходного несовпадения: обычные пользователи VPN штампуют несовпадения круглые сутки, а противоречия порождает только сознательное вмешательство. Вдобавок переопределённый геттер navigator.languages перестаёт отвечать [native code], когда скрипт заглядывает в его исходный код, — та самая примета, которой наша статья об обнаружении ботов посвящает целый раздел.
Единственный спуфинг, работающий в масштабе, — самый скучный. Tor Browser в английской конфигурации по умолчанию у всех отвечает одинаково — en-US,en;q=0.5 — и прячет ваш язык тем, что делает вас неотличимым от любого другого пользователя Tor. Этот размен — защита в обмен на то, что вы очевидно Tor, — честная версия того, что половинчатые расширения только изображают.
Что делать на практике
- Запустите проверку. Виджет на этой странице прямо сейчас сравнивает языки вашего браузера со страной вашего IP — по тем же соответствиям «страна — языки», которыми пользовался бы антифрод-скрипт. Прогоните его с включённым VPN, потому что именно из этой конфигурации складывается ваш риск-скоринг, а затем запустите полное сканирование браузера — там живут соседние проверки: часовой пояс, WebRTC, отпечатки.
- Переносите языки вместе с VPN. Чистое решение повторяет совет из статьи о часовом поясе: сделайте заявление правдой. Добавьте язык страны выхода в список языков браузера — в Chrome это
chrome://settings/languages, в Firefox раздел «Язык» — и, если хотите, оставьте рядом свой настоящий: большинство систем проверяют «подходит ли хоть один язык», а не «подходят ли все». Только делайте это в собственных настройках браузера, а не расширением, чтобы заголовок и JavaScript изменились вместе. - Если вы ведёте несколько личностей, страницей настроек тут не обойтись. Каждому профилю нужно, чтобы его языки, часовой пояс и IP рассказывали одну историю — в каждой сессии, а ручная правка настроек под каждую личность не переживает встречи с реальной работой. Incogniton выставляет язык каждого профиля под прокси этого профиля — сразу и в заголовке, и в JavaScript, — так что браузер никогда не спорит с собственными пакетами.
Ваш браузер уже сообщил последнему серверу, к которому вы обращались, на каком языке вы читаете. Виджет выше скажет, подтверждает ли ваш IP это заявление.