Wprowadzenie
Nie wiem, czy istnieje lub kiedykolwiek będzie sposób na jednoznaczną identyfikację maszyn za pomocą samej przeglądarki. Główne powody to:
- Będziesz musiał zapisać dane na komputerze użytkownika. Użytkownik może usunąć te dane w dowolnym momencie. Chyba że masz sposób na odtworzenie tych danych, które są unikalne dla każdej maszyny, a następnie utkniesz.
- Uprawomocnienie. Musisz chronić się przed fałszowaniem, przechwytywaniem sesji itp.
Nawet jeśli istnieją sposoby na śledzenie komputera bez użycia plików cookie, zawsze będzie sposób na obejście go i oprogramowanie, które zrobi to automatycznie. Jeśli naprawdę potrzebujesz śledzić coś na podstawie komputera, musisz napisać natywną aplikację (Apple Store / Android Store / Windows Program / etc).
Być może nie będę w stanie udzielić odpowiedzi na zadane pytanie, ale mogę pokazać, jak wdrożyć śledzenie sesji. Dzięki śledzeniu sesji próbujesz śledzić sesję przeglądania zamiast odwiedzania witryny przez komputer. Dzięki śledzeniu sesji schemat bazy danych będzie wyglądał następująco:
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
}, ...]
Zalety śledzenia na podstawie sesji:
- Dla zalogowanych użytkowników zawsze możesz wygenerować ten sam identyfikator sesji od użytkowników
username
/ password
/ email
.
- Nadal możesz śledzić użytkowników korzystających
sessionID
.
- Nawet jeśli kilka osób korzysta z tego samego komputera (np. Kafejka internetowa), możesz je śledzić osobno, jeśli się zalogują.
Wady śledzenia na podstawie sesji:
- Sesje są oparte na przeglądarce, a nie na komputerze. Jeśli użytkownik używa 2 różnych przeglądarek, spowoduje to 2 różne sesje. Jeśli jest to problem, możesz przestać czytać tutaj.
- Sesje wygasają, jeśli użytkownik nie jest zalogowany. Jeśli użytkownik nie jest zalogowany, wówczas użyje sesji gościa, która zostanie unieważniona, jeśli użytkownik usunie pliki cookie i pamięć podręczną przeglądarki.
Realizacja
Istnieje wiele sposobów realizacji tego. Nie sądzę, żebym mógł je wszystkie opisać. Po prostu wymienię moich ulubionych, co sprawi, że będzie to pozytywna odpowiedź . Pamiętaj o tym.
Podstawy
Będę śledzić sesję, używając tak zwanego wiecznego pliku cookie. Są to dane, które zostaną automatycznie odtworzone, nawet jeśli użytkownik usunie pliki cookie lub zaktualizuje przeglądarkę. Nie przetrwa jednak usunięcie zarówno plików cookie, jak i pamięci podręcznej przeglądania.
W tym celu wykorzystam mechanizm buforowania przeglądarki ( RFC ), API WebStorage ( MDN ) i pliki cookie przeglądarki ( RFC , Google Analytics ).
Prawny
Aby wykorzystać identyfikatory śledzenia, musisz dodać je zarówno do swojej polityki prywatności, jak i warunków korzystania, najlepiej w ramach poddziału Śledzenie . Będziemy używać następujących kluczy zarówno na, jak document.cookie
i na window.localStorage
:
- _ga : dane Google Analytics
- __utma : Śledzący plik cookie Google Analytics
- sid : SessionID
Upewnij się, że na wszystkich stronach korzystających ze śledzenia dołączasz linki do swojej polityki prywatności i warunków użytkowania.
Gdzie mam przechowywać dane sesji?
Możesz zapisać dane sesji w bazie danych witryny lub na komputerze użytkownika. Ponieważ zwykle pracuję na mniejszych witrynach (pozwalających na ponad 10 tysięcy ciągłych połączeń), które używają aplikacji innych firm (Google Analytics / Clicky / itp.), Najlepiej jest dla mnie przechowywać dane na komputerze klienta. Ma to następujące zalety:
- Brak wyszukiwania w bazie danych / narzutu / obciążenia / opóźnienia / spacji / itp.
- Użytkownik może usunąć swoje dane w dowolnym momencie, bez potrzeby pisania mi irytujących wiadomości e-mail.
i wady:
- Dane muszą być zaszyfrowane / odszyfrowane i podpisane / zweryfikowane, co tworzy obciążenie procesora na kliencie (nieźle) i na serwerze (bah!).
- Dane są usuwane, gdy użytkownik usuwa pliki cookie i pamięć podręczną. (tego naprawdę chcę)
- Dane są niedostępne dla analiz, gdy użytkownicy przechodzą do trybu offline. (dane analityczne tylko dla aktualnie przeglądających użytkowników)
UUIDS
- BrowserID : Unikalny identyfikator generowany z ciągu agenta użytkownika przeglądarki.
Browser|BrowserVersion|OS|OSVersion|Processor|MozzilaMajorVersion|GeckoMajorVersion
- ComputerID : Wygenerowano z adresu IP użytkownika i klucza sesji HTTPS.
getISP(requestIP)|getHTTPSClientKey()
- FingerPrintID : odcisk palca oparty na JavaScript oparty na zmodyfikowanym pliku fingerprint.js .
FingerPrint.get()
- SessionID : Losowy klucz generowany podczas pierwszej wizyty użytkownika w witrynie.
BrowserID|ComputerID|randombytes(256)
- GoogleID : Wygenerowano z
__utma
pliku cookie.getCookie(__utma).uniqueid
Mechanizm
Pewnego dnia oglądałem pokaz mojej wendy Williams z moją dziewczyną i byłem całkowicie przerażony, gdy prowadząca poradziła swoim widzom, aby usunęli historię przeglądarki przynajmniej raz w miesiącu. Usunięcie historii przeglądarki ma zwykle następujące skutki:
- Usuwa historię odwiedzanych stron internetowych.
- Usuwa pliki cookie i
window.localStorage
(aww man).
Większość współczesnych przeglądarek udostępnia tę opcję, ale nie bój się przyjaciół. Bo jest rozwiązanie. Przeglądarka ma mechanizm buforowania do przechowywania skryptów / obrazów i innych rzeczy. Zwykle nawet jeśli usuniemy naszą historię, ta pamięć podręczna przeglądarki nadal pozostaje. Wszystko, czego potrzebujemy, to sposób przechowywania naszych danych tutaj. Można to zrobić na 2 sposoby. Lepszym rozwiązaniem jest użycie obrazu SVG i przechowywanie naszych danych w jego tagach. W ten sposób dane można nadal wyodrębniać, nawet jeśli JavaScript jest wyłączony za pomocą flasha. Ponieważ jednak jest to trochę skomplikowane, pokażę inne podejście, które wykorzystuje JSONP ( Wikipedia )
przyklad.com/assets/js/tracking.js (aktualnie 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);
}
Teraz możemy uzyskać klucz sesji w dowolnym momencie:
window.__sid || window.localStorage.getItem("sid") || getCookie("sid") || ""
Jak sprawić, by tracking.js został w przeglądarce?
Możemy to osiągnąć za pomocą nagłówków HTTP Cache-Control , Last-Modified i ETag . Możemy użyć SessionID
wartości as dla nagłówka etag:
setHeaders({
"ETag": SessionID,
"Last-Modified": new Date(0).toUTCString(),
"Cache-Control": "private, max-age=31536000, s-max-age=31536000, must-revalidate"
})
Last-Modified
Nagłówek informuje przeglądarkę, że ten plik zasadniczo nigdy nie jest modyfikowany. Cache-Control
informuje serwery proxy i bramy, aby nie buforowały dokumentu, ale przeglądarkę buforuje go przez 1 rok.
Następnym razem, gdy przeglądarka zażąda dokumentu, wyśle If-Modified-Since
i If-None-Match
nagłówki. Możemy użyć ich do zwrócenia 304 Not Modified
odpowiedzi.
przyklad.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();
}
Teraz za każdym razem, gdy przeglądarka zażąda, tracking.js
nasz serwer odpowie 304 Not Modified
wynikiem i wymusi wykonanie lokalnej kopii tracking.js
.
Nadal nie rozumiem. Wyjaśnij mi to
Załóżmy, że użytkownik czyści historię przeglądania i odświeża stronę. Na komputerze użytkownika pozostaje tylko kopia tracking.js
pamięci podręcznej przeglądarki. Gdy przeglądarka zażąda tracking.js
, otrzymuje 304 Not Modified
odpowiedź, która powoduje wykonanie pierwszej tracking.js
otrzymanej wersji . tracking.js
wykonuje i przywraca SessionID
usunięte dane.
Uprawomocnienie
Załóżmy, że Haxor X kradnie ciasteczka naszych klientów, gdy są jeszcze zalogowani. Jak je chronić? Kryptografia i odciski palców przeglądarki na ratunek. Pamiętaj, że nasza pierwotna definicja SessionID
brzmiała:
BrowserID|ComputerID|randomBytes(256)
Możemy to zmienić na:
Timestamp|BrowserID|ComputerID|encrypt(randomBytes(256), hk)|sign(Timestamp|BrowserID|ComputerID|randomBytes(256), hk)
Gdzie hk = sign(Timestamp|BrowserID|ComputerID, serverKey)
.
Teraz możemy zweryfikować nasz SessionID
przy użyciu następującego algorytmu:
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;
Teraz, aby atak Haxora zadziałał, muszą:
- Miej to samo
ComputerID
. Oznacza to, że muszą mieć tego samego dostawcę usług internetowych co ofiara (Tricky). To da naszej ofierze możliwość podjęcia kroków prawnych we własnym kraju. Haxor musi także uzyskać klucz sesji HTTPS od ofiary (trudny).
- Miej to samo
BrowserID
. Każdy może sfałszować ciąg User-Agent (irytujące).
- Być w stanie stworzyć własne fałszywe
SessionID
(Very Hard). Ataki woluminów nie będą działać, ponieważ używamy znacznika czasu do generowania klucza szyfrowania / podpisywania, więc zasadniczo przypomina to generowanie nowego klucza dla każdej sesji. Ponadto szyfrujemy losowe bajty, więc prosty atak słownikowy również nie wchodzi w rachubę.
Możemy poprawić sprawdzanie poprawności poprzez przekazywanie GoogleID
i FingerprintID
(poprzez ajax lub ukryte pola) i dopasowanie do nich.
if( GoogleID != getStoredGoodleID($sid) ) return false;
if( byte_difference(FingerPrintID, getStoredFingerprint($sid) > 10%) return false;