Pull to refresh

Постоянные неблокируемые cookie с использованием HTTP-заголовков

Reading time 3 min
Views 9.5K
Original author: Nik Cubrilovic
На прошлой неделе прогремела новость об исследовании, утверждающем, что аналитическая компания KissMetrics отслеживала пользователей на сайтах при помощи уникального значения заголовка ETag(спека). KissMetrics отрицали использование ETag и в итоге подали в суд на авторов исследования(см. upd. в конце статьи).

Использование ETag (сокрашение от 'element tag', «метка элемента») для отслеживания пользователей известен и используется в партнерских сетях с начала прошлого десятилетия. Так же известно, что и заголовок Last-Modified(spec) теоретически может использоваться для отслеживания пользователей с помощью уникального значения времени обновления.

Мне, правда, кажется, что мало кто знает, что заголовок Last-Modified может принимать в качестве значения любую строку, то есть значение не обязательно должно быть правильной датой.

Лучше всего показать это на примере. Данный пример использует мою страницу, которая устанавливает разные значения для даты последнего изменения. Если обновить страницу после установки значения даты, можно заметить, что браузер отсылает это значение обратно.

Первый запрос

Превый запрос к серверу выглядит так. Ничего необычного не происходит.

GET /tracking-cookie HTTP/1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cache-Control: max-age=0
Host: nikcub.appspot.com
User-Agent: Mozilla/5.0


Ответ сервера: устанавливам токен

Сервер отвечает и устанавливает уникальный идентификатор (в данном случае UUID) в качестве значения для Last-Modified:

HTTP/1.0 200 OK
Server: Dev/1.0
Date: Sat, 19 August 2011 7:48:25 GMT
Content-type: text/html; charset=utf8
    Last-Modified: d5ee23de-ca05-11e0-ab0b-c336b05508a0
Cache-Control: no-cache
Content-Length: 1634


Обратите внимание, что обычно, если этот способ кэширования данных используется, значением будет стандартная строка с временем:

Last-Modified: Sat, 29 Oct 1994 19:43:31 GMT

Последующие вызовы

Браузер теперь будет отсылать этот токен при каждом вызове к тому же URI, используя заголовок If-Modified-Since(спека). Браузер спрашивает: «Если дата изменения данного ресурса позже, чем эта дата, пришли его мне», но при этом отсылает уникальный идентификатор, а не дату.

GET /tracking-cookie HTTP/1.1
Host: nikcub.appspot.com
Connection: keep-alive
Cache-Control: max-age=0
User-Agent: Mozilla/5.0
    If-Modified-Since: d5ee23de-ca05-11e0-ab0b-c336b05508a0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3


Это срабатывает даже, если закрыть браузер и открыть его заново, и срабатывает во всех основных браузерах. Метод, основанный на ETag'ах работает не всегда, особенно если на пути стоят web-прокси, а вот метод, основанный на Last-Modified срабатывает всегда.

Решения

Проблема с этими методами заключается в том, что они обходят пользовательские и программные настройки безопасности, связанные с cookie. Можно заблокировать любые cookie, но ETag, Last-Modifed и другие методы все равно позволят отслеживать ваш браузер.

В спецификации Last-Modified указано, что значение должно быть датой, но с примечанием, что в случае несинхронизированных часов могут возникнуть возможные проблемы. Большинство библиотечных реализаций просто отсылают это значение обратно без проверки, в частности потому что парсинг дат — это сплошная головная боль. Браузеры поступают так же, что приводит к наличию описываемой проблемы. Это значит, что Last-Modified работает как cookie, но без каких-либо проверок по безопасности.

Я отошлю bug report во все браузеры с открытым исходным кодом с просьбой корректно парсить даты. Это не стопроцентное решение, так как можно продолжать отследивать пользователей, используя уникальные даты. Но, возможно, будет найден решение в виде приведения даты к ближайшему часу или других базовых проверок на валидность даты. Другого решения, кроме как очистить и отключить кэш, нет, но условные GET-запросы все равно происходят во время браузерной сессии в некоторых браузерах.

Можете сами убедиться в этой проблеме на моей странице.

Дополнение: Плагин для конфиденциальных данных, над которым я работаю, Parley, решит эту проблему, так как он блокирует запросы с любых сторонних сайтов. Я думаю о том, чтобы добавить к нему и парсинг дат. Вот над чем придется поработать, когда я снова возьмусь за этот проект (плагины могут немногое, и иногда возникает соблазн создать форк WebKit'а и сделать собственный безопасный браузер).

Upd. Компания KissMetrics не подавала в суд на авторов исследования, а подала встречный иск против юридической компании и клиентов этой компании, которые подали на KissMetrics в суд. Автор исследования, Ashkan Soltani, к этим искам отношения не имеет.
Tags:
Hubs:
+69
Comments 71
Comments Comments 71

Articles