Введение
Я не знаю, есть ли или когда-нибудь найдется способ уникальной идентификации машин с помощью одного браузера. Основными причинами являются:
- Вам нужно будет сохранить данные на компьютере пользователя. Эти данные могут быть удалены пользователем в любое время. Если у вас нет способа воссоздать эти данные, которые являются уникальными для каждой машины, то вы застряли.
- Проверка. Вы должны остерегаться подделки, перехвата сеанса и т. Д.
Даже если есть способы отследить компьютер без использования файлов cookie, всегда найдется способ обойти его и программное обеспечение, которое сделает это автоматически. Если вам действительно нужно что-то отслеживать на компьютере, вам придется написать собственное приложение (Apple Store / Android Store / Windows Program / etc).
Возможно, я не смогу дать вам ответ на заданный вами вопрос, но я покажу вам, как реализовать отслеживание сеансов. С помощью отслеживания сеанса вы пытаетесь отслеживать сеанс просмотра, а не компьютер, посещающий ваш сайт. Отслеживая сеанс, ваша схема базы данных будет выглядеть так:
sesssion:
sessionID: string
// Global session data goes here
computers: [{
BrowserID: string
ComputerID: string
FingerprintID: string
userID: string
authToken: string
ipAddresses: ["203.525....", "203.525...", ...]
// Computer session data goes here
}, ...]
Преимущества отслеживания на основе сеанса:
- Для зарегистрированных пользователей вы всегда можете сгенерировать один и тот же идентификатор сессии из пользователей
username
/ password
/ email
.
- Вы все еще можете отслеживать гостевых пользователей, используя
sessionID
.
- Даже если несколько человек используют один и тот же компьютер (например, интернет-кафе), вы можете отслеживать их отдельно, если они вошли в систему.
Недостатки отслеживания на основе сеанса:
- Сессии основаны на браузере, а не на компьютере. Если пользователь использует 2 разных браузера, это приведет к 2 разным сеансам. Если это проблема, вы можете перестать читать здесь.
- Сессии истекают, если пользователь не вошел в систему. Если пользователь не вошел в систему, то он будет использовать гостевой сеанс, который будет признан недействительным, если пользователь удалит файлы cookie и кэш браузера.
Реализация
Есть много способов реализации этого. Я не думаю, что смогу охватить их все, я просто перечислю свою любимую, что сделало бы этот самоуверенный ответ . Имейте это в виду.
основы
Я буду отслеживать сессию, используя так называемый файл cookie навсегда. Это данные, которые автоматически воссоздают себя, даже если пользователь удаляет свои куки или обновляет свой браузер. Тем не менее, пользователь не сможет удалить и свои куки, и кеш браузера.
Для реализации этого я буду использовать механизм кэширования браузеров ( RFC ), API WebStorage ( MDN ) и куки-файлы браузера ( RFC , Google Analytics ).
легальный
Чтобы использовать идентификаторы отслеживания, вам необходимо добавить их как в вашу политику конфиденциальности, так и в условия использования, предпочтительно в разделе « Отслеживание» . Мы будем использовать следующие клавиши на обоих document.cookie
и window.localStorage
:
- _ga : данные Google Analytics
- __utma : файл cookie для отслеживания Google Analytics
- sid : SessionID
Убедитесь, что вы включили ссылки на свою Политику конфиденциальности и условия использования на всех страницах, которые используют отслеживание.
Где я могу хранить свои данные сеанса?
Вы можете сохранить данные сеанса в базе данных вашего веб-сайта или на компьютере пользователя. Поскольку я обычно работаю на небольших сайтах (пусть более 10 тысяч непрерывных подключений), которые используют сторонние приложения (Google Analytics / Clicky / etc), лучше всего хранить данные на клиентском компьютере. Это имеет следующие преимущества:
- Нет поиска в базе данных / накладные расходы / нагрузка / задержка / пробел / т. Д.
- Пользователь может удалить свои данные в любое время без необходимости писать мне надоедливые электронные письма.
и недостатки:
- Данные должны быть зашифрованы / дешифрованы и подписаны / проверены, что создает накладные расходы процессора на клиенте (не так уж плохо) и на сервере (ба!).
- Данные удаляются, когда пользователь удаляет свои куки и кеш. (это то, что я действительно хочу)
- Данные недоступны для аналитики, когда пользователи выходят в автономный режим. (аналитика только для пользователей, просматривающих в настоящее время)
UUIDs
- BrowserID : уникальный идентификатор, сгенерированный из строки пользовательского агента браузера.
Browser|BrowserVersion|OS|OSVersion|Processor|MozzilaMajorVersion|GeckoMajorVersion
- ComputerID : генерируется из IP-адреса пользователя и сеансового ключа HTTPS.
getISP(requestIP)|getHTTPSClientKey()
- FingerPrintID : снятие отпечатков на основе JavaScript на основе измененного fingerprint.js .
FingerPrint.get()
- SessionID : случайный ключ, генерируемый при первом посещении сайта пользователем.
BrowserID|ComputerID|randombytes(256)
- GoogleID : создан из
__utma
cookie.getCookie(__utma).uniqueid
Механизм
На днях я смотрел шоу Венди Уильямс с моей подругой и был совершенно в ужасе, когда хозяин посоветовал своим зрителям удалять историю браузера по крайней мере раз в месяц. Удаление истории браузера обычно имеет следующие эффекты:
- Удаляет историю посещенных сайтов.
- Удаляет печенье и
window.localStorage
(ооо человек).
Большинство современных браузеров делают эту опцию доступной, но не бойтесь друзей. Ибо есть решение. В браузере есть механизм кеширования для хранения скриптов / изображений и прочего. Обычно, даже если мы удаляем нашу историю, этот кеш браузера остается. Все, что нам нужно, это способ хранить наши данные здесь. Есть 2 способа сделать это. Лучше использовать SVG-изображение и хранить наши данные в его тегах. Таким образом, данные могут быть извлечены, даже если JavaScript отключен с помощью Flash. Однако, поскольку это немного сложно, я продемонстрирую другой подход, который использует JSONP ( Википедия )
example.com/assets/js/tracking.js (на самом деле tracking.php)
var now = new Date();
var window.__sid = "SessionID"; // Server generated
setCookie("sid", window.__sid, now.setFullYear(now.getFullYear() + 1, now.getMonth(), now.getDate() - 1));
if( "localStorage" in window ) {
window.localStorage.setItem("sid", window.__sid);
}
Теперь мы можем получить наш сессионный ключ в любое время:
window.__sid || window.localStorage.getItem("sid") || getCookie("sid") || ""
Как мне сделать track.js в браузере?
Мы можем добиться этого, используя HTTP-заголовки Cache-Control , Last-Modified и ETag . Мы можем использовать SessionID
как значение для заголовка etag:
setHeaders({
"ETag": SessionID,
"Last-Modified": new Date(0).toUTCString(),
"Cache-Control": "private, max-age=31536000, s-max-age=31536000, must-revalidate"
})
Last-Modified
Заголовок сообщает браузеру, что этот файл практически никогда не изменяется. Cache-Control
говорит прокси и шлюзам не кэшировать документ, но сообщает браузеру кэшировать его в течение 1 года.
В следующий раз, когда браузер запросит документ, он отправит If-Modified-Since
и If-None-Match
заголовки. Мы можем использовать их, чтобы вернуть 304 Not Modified
ответ.
example.com/assets/js/tracking.php
$sid = getHeader("If-None-Match") ?: getHeader("if-none-match") ?: getHeader("IF-NONE-MATCH") ?: "";
$ifModifiedSince = hasHeader("If-Modified-Since") ?: hasHeader("if-modified-since") ?: hasHeader("IF-MODIFIED-SINCE");
if( validateSession($sid) ) {
if( sessionExists($sid) ) {
continueSession($sid);
send304();
} else {
startSession($sid);
send304();
}
} else if( $ifModifiedSince ) {
send304();
} else {
startSession();
send200();
}
Теперь каждый раз, когда браузер запрашивает, tracking.js
наш сервер ответит 304 Not Modified
результатом и принудительно выполнит локальную копию tracking.js
.
Я до сих пор не понимаю. Объясни мне
Предположим, что пользователь очищает свою историю просмотров и обновляет страницу. Единственное, что осталось на компьютере пользователя - это копия tracking.js
в кеше браузера. Когда браузер запрашивает, tracking.js
он получает 304 Not Modified
ответ, который заставляет его выполнить первую версиюtracking.js
. tracking.js
выполняет и восстанавливает то, SessionID
что было удалено.
Проверка
Предположим, Haxor X крадет файлы cookie наших клиентов, пока они еще вошли в систему. Как мы защищаем их? Криптография и браузер снимают отпечатки пальцев на помощь. Запомните наше первоначальное определение SessionID
:
BrowserID|ComputerID|randomBytes(256)
Мы можем изменить это на:
Timestamp|BrowserID|ComputerID|encrypt(randomBytes(256), hk)|sign(Timestamp|BrowserID|ComputerID|randomBytes(256), hk)
куда hk = sign(Timestamp|BrowserID|ComputerID, serverKey)
.
Теперь мы можем проверить наши, SessionID
используя следующий алгоритм:
if( getTimestamp($sid) is older than 1 year ) return false;
if( getBrowserID($sid) !== createBrowserID($_Request, $_Server) ) return false;
if( getComputerID($sid) !== createComputerID($_Request, $_Server) return false;
$hk = sign(getTimestamp($sid) + getBrowserID($sid) + getComputerID($sid), $SERVER["key"]);
if( !verify(getTimestamp($sid) + getBrowserID($sid) + getComputerID($sid) + decrypt(getRandomBytes($sid), hk), getSignature($sid), $hk) ) return false;
return true;
Теперь, чтобы атака Хаксора сработала, они должны:
- Есть же
ComputerID
. Это означает, что у них должен быть тот же провайдер, что и у жертвы (Tricky). Это даст нашей жертве возможность подать в суд на свою страну. Хаксор также должен получить ключ сеанса HTTPS от жертвы (Hard).
- Есть же
BrowserID
. Любой может подделать строку User-Agent (раздражает).
- Уметь создавать свои собственные подделки
SessionID
(Very Hard). Объемные атаки не будут работать, потому что мы используем временную метку для генерации ключа шифрования / подписи, так что в основном это похоже на генерацию нового ключа для каждой сессии. Кроме того, мы шифруем случайные байты, поэтому о простой атаке по словарю также не может быть и речи.
Мы можем улучшить валидацию, перенаправляя GoogleID
и FingerprintID
(через ajax или скрытые поля) и сопоставляя их.
if( GoogleID != getStoredGoodleID($sid) ) return false;
if( byte_difference(FingerPrintID, getStoredFingerprint($sid) > 10%) return false;