Введение
Я не знаю, есть ли или когда-нибудь найдется способ уникальной идентификации машин с помощью одного браузера. Основными причинами являются:
- Вам нужно будет сохранить данные на компьютере пользователя. Эти данные могут быть
удаляется пользователем в любое время. Если у вас нет способа воссоздать это
данные, которые являются уникальными для каждой машины, то застряли.
- проверка. Вы должны остерегаться подделки, перехвата сеанса и т. Д.
Даже если есть способы отслеживания компьютера без использования файлов 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 Аналитика ).
Правовая
Чтобы использовать идентификаторы отслеживания, вам необходимо добавить их как в вашу политику конфиденциальности, так и в условия использования, предпочтительно в подзаголовке Отслеживание . Мы будем использовать следующие клавиши на 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
(aww man).
Большинство современных браузеров делают эту опцию доступной, но не бойтесь друзей. Ибо есть решение. В браузере есть механизм кэширования для хранения скриптов / изображений и прочего. Обычно, даже если мы удаляем нашу историю, этот кеш браузера остается. Все, что нам нужно, это способ хранения наших данных здесь. Есть 2 способа сделать это. Лучше использовать SVG-изображение и хранить наши данные в его тегах. Таким образом, данные могут быть извлечены, даже если JavaScript отключен с помощью Flash. Однако, поскольку это немного сложно, я продемонстрирую другой подход, который использует JSONP ( Wikipedia )
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") || ""
Как сделать, чтобы tracking.js вставлялся в браузер?
Этого можно добиться, используя Cache-Control , Last-Modified и ETag HTTP-заголовки. Мы можем использовать 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 / активы / 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(decrypt(getRandomBytes($sid)), getSignature($sid), $hk) ) return false;
return true;
Теперь, чтобы атака Хаксора сработала, они должны:
- Иметь такой же
ComputerID
. Это означает, что у них должен быть тот же поставщик услуг Интернета, что и у жертвы (Tricky). Это даст нашей жертве возможность подать в суд на свою страну. Хаксор также должен получить ключ сеанса HTTPS от жертвы (Hard).
- Иметь такой же
BrowserID
. Любой может подменить строку User-Agent (раздражает). - Уметь создавать собственную фальшивку
SessionID
(Очень сложно). Объемные атаки не будут работать, потому что мы используем временную метку для генерации ключа шифрования / подписи, так что в основном это похоже на генерацию нового ключа для каждой сессии. Кроме того, мы шифруем случайные байты, поэтому о простой атаке по словарю также не может быть и речи.
Мы можем улучшить валидацию, перенаправив GoogleID
и FingerprintID
(через ajax или скрытые поля) и сопоставив с ними.
if( GoogleID != getStoredGoodleID($sid) ) return false;
if( byte_difference(FingerPrintID, getStoredFingerprint($sid) > 10%) return false;