Введение
Я не знаю, существует ли или когда-либо будет способ однозначно идентифицировать машины, используя только браузер. Основные причины:
- Вам нужно будет сохранить данные на компьютере пользователя. Эти данные могут быть удалены пользователем в любое время. Если у вас нет способа воссоздать эти данные, уникальные для каждой машины, тогда вы застряли.
- Проверка. Вам необходимо принять меры против спуфинга, перехвата сеанса и т. Д.
Даже если есть способы отслеживать компьютер без использования файлов cookie, всегда будет способ обойти его и программное обеспечение, которое сделает это автоматически. Если вам действительно нужно что-то отслеживать на компьютере, вам придется написать собственное приложение (Apple Store / Android Store / Windows Program / и т. Д.).
Возможно, я не смогу дать вам ответ на заданный вами вопрос, но я могу показать вам, как реализовать отслеживание сеансов. С отслеживанием сеанса вы пытаетесь отслеживать сеанс просмотра, а не компьютер, посещающий ваш сайт. При отслеживании сеанса схема вашей базы данных будет выглядеть так:
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 навсегда. Это данные, которые автоматически воссоздаются, даже если пользователь удалит свои файлы cookie или обновит свой браузер. Однако он не сможет выжить, если пользователь удалит как свои файлы cookie, так и кеш просмотра.
Для реализации этого я буду использовать механизм кеширования браузеров (RFC), WebStorage API ( MDN) и файлы cookie браузера (RFC, Google Analytics).
Юридический
Чтобы использовать идентификаторы отслеживания, вам необходимо добавить их как в свою политику конфиденциальности, так и в условия использования, желательно в подзаголовке Отслеживание. Мы будем использовать следующие ключи как на document.cookie
, так и на window.localStorage
:
- _ga: данные Google Analytics.
- __utma: файл cookie отслеживания Google Analytics.
- sid: SessionID
Убедитесь, что вы разместили ссылки на свою Политику конфиденциальности и условия использования на всех страницах, на которых используется отслеживание.
Где мне хранить данные моего сеанса?
Вы можете хранить данные сеанса в базе данных вашего веб-сайта или на компьютере пользователя. Поскольку я обычно работаю на небольших сайтах (допускается более 10 тысяч непрерывных подключений), которые используют сторонние приложения (Google Analytics / Clicky и т. Д.), Мне лучше всего хранить данные на компьютере клиента. Это дает следующие преимущества:
- Нет поиска в базе данных / накладных расходов / нагрузки / задержки / места / и т. Д.
- Пользователь может удалить свои данные, когда захочет, без необходимости писать мне надоедливые электронные письма.
и недостатки:
- Данные должны быть зашифрованы / дешифрованы и подписаны / проверены, что создает накладные расходы на ЦП на клиенте (не так уж и плохо) и на сервере (да!).
- Данные удаляются, когда пользователь удаляет свои файлы cookie и кеш. (это то, что я действительно хочу)
- Данные недоступны для аналитики, когда пользователи отключены. (аналитика только для просматриваемых в данный момент пользователей)
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
Механизм
На днях я смотрел шоу Венди Уильямс со своей девушкой и был в полном ужасе, когда ведущий посоветовал своим зрителям удалить историю их браузера не реже одного раза в месяц. Удаление истории браузера обычно имеет следующие эффекты:
- Удаляет историю посещенных сайтов.
- Удаляет файлы cookie и
window.localStorage
(оу, человек).
Большинство современных браузеров делают эту опцию легко доступной, но не бойтесь, друзья. Ибо выход есть. В браузере есть механизм кеширования для хранения скриптов / изображений и прочего. Обычно, даже если мы удаляем нашу историю, этот кеш браузера все равно остается. Все, что нам нужно, это способ хранить здесь наши данные. Есть 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/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). Это даст нашей жертве возможность подать в суд в своей стране. Haxor также должен получить сеансовый ключ HTTPS от жертвы (Hard).
- Есть такой же
BrowserID
. Кто угодно может подделать строку User-Agent (раздражает).
- Уметь создавать свои подделки
SessionID
(Очень сложно). Объемные атаки не будут работать, потому что мы используем временную метку для генерации ключа шифрования / подписи, так что в основном это похоже на создание нового ключа для каждого сеанса. Кроме того, мы шифруем случайные байты, поэтому простая атака по словарю также исключена.
Мы можем улучшить проверку, пересылая GoogleID
и FingerprintID
(через ajax или скрытые поля) и сопоставляя их.
if( GoogleID != getStoredGoodleID($sid) ) return false;
if( byte_difference(FingerPrintID, getStoredFingerprint($sid) > 10%) return false;
person
Walter
schedule
10.01.2017