Einführung
Wenn ich Sie richtig verstehe, müssen Sie einen Benutzer identifizieren, für den Sie keine eindeutige Kennung haben. Sie möchten also herausfinden, wer er ist, indem Sie zufällige Daten abgleichen. Sie können die Identität des Benutzers nicht zuverlässig speichern, weil:
- Cookies können gelöscht werden
- IP-Adresse Kann sich ändern
- Browser kann sich ändern
- Der Browser-Cache wird möglicherweise gelöscht
Ein Java-Applet oder Com-Objekt wäre eine einfache Lösung mit einem Hash von Hardwareinformationen gewesen, aber heutzutage sind die Benutzer so sicherheitsbewusst, dass es schwierig ist, Benutzer dazu zu bringen, diese Art von Programmen auf ihrem System zu installieren. Dies führt dazu, dass Sie keine Cookies und andere ähnliche Tools verwenden müssen.
Cookies und andere ähnliche Tools
Sie können ein Datenprofil erstellen und dann mithilfe von Wahrscheinlichkeitstests einen wahrscheinlichen Benutzer identifizieren . Ein hierfür nützliches Profil kann durch eine Kombination der folgenden Elemente erstellt werden:
- IP Adresse
- Echte IP-Adresse
- Proxy-IP-Adresse (Benutzer verwenden häufig denselben Proxy wiederholt)
- Kekse
- Web-Fehler (weniger zuverlässig, da Fehler behoben werden, aber dennoch nützlich sind)
- PDF Bug
- Flash Bug
- Java Bug
- Browser
- Klicken Sie auf Tracking (viele Benutzer besuchen bei jedem Besuch dieselbe Seitenreihe).
- Browser Fingerabdruck - Installierte Plugins (Menschen haben oft unterschiedliche, etwas einzigartige Sätze von Plugins)
- Zwischengespeicherte Bilder (Leute löschen manchmal ihre Cookies, lassen aber zwischengespeicherte Bilder)
- Blobs verwenden
- URL (s) (Browserverlauf oder Cookies können eindeutige Benutzer-IDs in URLs enthalten, z. B. https://stackoverflow.com/users/1226894 oder http://www.facebook.com/barackobama?fref=ts )
- Erkennung von Systemschriftarten (dies ist eine wenig bekannte, aber häufig eindeutige Schlüsselsignatur)
- HTML5 & Javascript
- HTML5 LocalStorage
- HTML5 Geolocation API und Reverse Geocoding
- Architektur, Betriebssystemsprache, Systemzeit, Bildschirmauflösung usw.
- Netzwerkinformations-API
- Batteriestatus-API
Die von mir aufgelisteten Elemente sind natürlich nur einige Möglichkeiten, wie ein Benutzer eindeutig identifiziert werden kann. Es gibt viele mehr.
Wie geht es mit diesem Satz zufälliger Datenelemente weiter, aus denen ein Datenprofil erstellt werden soll?
Der nächste Schritt ist die Entwicklung einer Fuzzy-Logik oder, noch besser, eines künstlichen neuronalen Netzwerks (das Fuzzy-Logik verwendet). In beiden Fällen besteht die Idee darin, Ihr System zu trainieren und dann sein Training mit Bayesian Inference zu kombinieren , um die Genauigkeit Ihrer Ergebnisse zu erhöhen.
Mit der NeuralMesh- Bibliothek für PHP können Sie künstliche neuronale Netze generieren. Überprüfen Sie die folgenden Links, um die Bayes'sche Inferenz zu implementieren:
An diesem Punkt denken Sie vielleicht:
Warum so viel Mathematik und Logik für eine scheinbar einfache Aufgabe?
Grundsätzlich, weil es keine einfache Aufgabe ist . Was Sie erreichen möchten, ist in der Tat reine Wahrscheinlichkeit . Zum Beispiel bei folgenden bekannten Benutzern:
User1 = A + B + C + D + G + K
User2 = C + D + I + J + K + F
Wenn Sie folgende Daten erhalten:
B + C + E + G + F + K
Die Frage, die Sie im Wesentlichen stellen, lautet:
Wie groß ist die Wahrscheinlichkeit, dass die empfangenen Daten (B + C + E + G + F + K) tatsächlich Benutzer1 oder Benutzer2 sind? Und welches dieser beiden Spiele ist am wahrscheinlichsten?
Um diese Frage effektiv beantworten zu können, müssen Sie das Format Frequenz gegen Wahrscheinlichkeit verstehen und wissen, warum die gemeinsame Wahrscheinlichkeit ein besserer Ansatz sein könnte. Die Details sind zu umfangreich, um hier näher darauf einzugehen (weshalb ich Ihnen Links gebe), aber ein gutes Beispiel wäre eine Anwendung des Assistenten für medizinische Diagnosen , die eine Kombination von Symptomen verwendet, um mögliche Krankheiten zu identifizieren.
Stellen Sie sich für einen Moment die Reihe von Datenpunkten vor, aus denen Ihr Datenprofil (B + C + E + G + F + K im obigen Beispiel) als Symptome und unbekannte Benutzer als Krankheiten besteht . Indem Sie die Krankheit identifizieren, können Sie eine geeignete Behandlung identifizieren (behandeln Sie diesen Benutzer als Benutzer1).
Offensichtlich ist eine Krankheit, für die wir mehr als ein Symptom identifiziert haben, leichter zu identifizieren. Je mehr Symptome wir identifizieren können, desto einfacher und genauer ist unsere Diagnose.
Gibt es noch andere Alternativen?
Natürlich. Als alternative Maßnahme können Sie Ihren eigenen einfachen Bewertungsalgorithmus erstellen und ihn auf exakten Übereinstimmungen basieren. Dies ist nicht so effizient wie die Wahrscheinlichkeit, kann jedoch für Sie einfacher zu implementieren sein.
Betrachten Sie als Beispiel diese einfache Punktetabelle:
+ ------------------------- + -------- + ------------ +
| Eigentum | Gewicht | Bedeutung |
+ ------------------------- + -------- + ------------ +
| Echte IP-Adresse | 60 | 5 |
| Verwendete Proxy-IP-Adresse | 40 | 4 |
| HTTP-Cookies | 80 | 8 |
| Sitzungscookies | 80 | 6 |
| Cookies von Drittanbietern | 60 | 4 |
| Flash-Cookies | 90 | 7 |
| PDF Bug | 20 | 1 |
| Flash Bug | 20 | 1 |
| Java Bug | 20 | 1 |
| Häufige Seiten | 40 | 1 |
| Browser Fingerabdruck | 35 | 2 |
| Installierte Plugins | 25 | 1 |
| Zwischengespeicherte Bilder | 40 | 3 |
| URL | 60 | 4 |
| Systemschriftartenerkennung | 70 | 4 |
| Localstorage | 90 | 8 |
| Geolocation | 70 | 6 |
| AOLTR | 70 | 4 |
| Netzwerkinformations-API | 40 | 3 |
| Batteriestatus-API | 20 | 1 |
+ ------------------------- + -------- + ------------ +
Vergeben Sie für jede Information, die Sie auf eine bestimmte Anfrage sammeln können, die zugehörige Punktzahl und verwenden Sie dann Wichtigkeit , um Konflikte zu lösen, wenn die Punktzahlen gleich sind.
Konzeptioneller Beweiß
Für einen einfachen Proof of Concept werfen Sie bitte einen Blick auf Perceptron . Perceptron ist ein RNA-Modell , das im Allgemeinen in Mustererkennungsanwendungen verwendet wird. Es gibt sogar eine alte PHP-Klasse, die sie perfekt implementiert, aber Sie müssten sie wahrscheinlich für Ihre Zwecke ändern.
Obwohl Perceptron ein großartiges Tool ist, kann es dennoch mehrere Ergebnisse (mögliche Übereinstimmungen) zurückgeben. Daher ist die Verwendung eines Vergleichs von Punktzahl und Differenz immer noch nützlich, um die besten dieser Übereinstimmungen zu ermitteln.
Annahmen
- Speichern Sie alle möglichen Informationen zu jedem Benutzer (IP, Cookies usw.).
- Wenn das Ergebnis genau übereinstimmt, erhöhen Sie die Punktzahl um 1
- Wenn das Ergebnis nicht exakt übereinstimmt, verringern Sie die Punktzahl um 1
Erwartung
- RNA-Markierungen generieren
- Generieren Sie zufällige Benutzer, die eine Datenbank emulieren
- Generieren Sie einen einzelnen unbekannten Benutzer
- Generieren Sie unbekannte Benutzer-RNA und -Werte
- Das System wird RNA-Informationen zusammenführen und das Perceptron lehren
- Nach dem Training des Perceptron hat das System eine Reihe von Gewichtungen
- Sie können jetzt das Muster des unbekannten Benutzers testen und das Perceptron erstellt eine Ergebnismenge.
- Speichern Sie alle positiven Übereinstimmungen
- Sortieren Sie die Übereinstimmungen zuerst nach Punktzahl und dann nach Differenz (wie oben beschrieben).
- Geben Sie die zwei engsten Übereinstimmungen aus oder geben Sie leere Ergebnisse aus, wenn keine Übereinstimmungen gefunden werden
Code für Proof of Concept
$features = array(
'Real IP address' => .5,
'Used proxy IP address' => .4,
'HTTP Cookies' => .9,
'Session Cookies' => .6,
'3rd Party Cookies' => .6,
'Flash Cookies' => .7,
'PDF Bug' => .2,
'Flash Bug' => .2,
'Java Bug' => .2,
'Frequent Pages' => .3,
'Browsers Finger Print' => .3,
'Installed Plugins' => .2,
'URL' => .5,
'Cached PNG' => .4,
'System Fonts Detection' => .6,
'Localstorage' => .8,
'Geolocation' => .6,
'AOLTR' => .4,
'Network Information API' => .3,
'Battery Status API' => .2
);
// Get RNA Lables
$labels = array();
$n = 1;
foreach ($features as $k => $v) {
$labels[$k] = "x" . $n;
$n ++;
}
// Create Users
$users = array();
for($i = 0, $name = "A"; $i < 5; $i ++, $name ++) {
$users[] = new Profile($name, $features);
}
// Generate Unknown User
$unknown = new Profile("Unknown", $features);
// Generate Unknown RNA
$unknownRNA = array(
0 => array("o" => 1),
1 => array("o" => - 1)
);
// Create RNA Values
foreach ($unknown->data as $item => $point) {
$unknownRNA[0][$labels[$item]] = $point;
$unknownRNA[1][$labels[$item]] = (- 1 * $point);
}
// Start Perception Class
$perceptron = new Perceptron();
// Train Results
$trainResult = $perceptron->train($unknownRNA, 1, 1);
// Find matches
foreach ($users as $name => &$profile) {
// Use shorter labels
$data = array_combine($labels, $profile->data);
if ($perceptron->testCase($data, $trainResult) == true) {
$score = $diff = 0;
// Determing the score and diffrennce
foreach ($unknown->data as $item => $found) {
if ($unknown->data[$item] === $profile->data[$item]) {
if ($profile->data[$item] > 0) {
$score += $features[$item];
} else {
$diff += $features[$item];
}
}
}
// Ser score and diff
$profile->setScore($score, $diff);
$matchs[] = $profile;
}
}
// Sort bases on score and Output
if (count($matchs) > 1) {
usort($matchs, function ($a, $b) {
// If score is the same use diffrence
if ($a->score == $b->score) {
// Lower the diffrence the better
return $a->diff == $b->diff ? 0 : ($a->diff > $b->diff ? 1 : - 1);
}
// The higher the score the better
return $a->score > $b->score ? - 1 : 1;
});
echo "<br />Possible Match ", implode(",", array_slice(array_map(function ($v) {
return sprintf(" %s (%0.4f|%0.4f) ", $v->name, $v->score,$v->diff);
}, $matchs), 0, 2));
} else {
echo "<br />No match Found ";
}
Ausgabe:
Possible Match D (0.7416|0.16853),C (0.5393|0.2809)
Print_r von "D":
echo "<pre>";
print_r($matchs[0]);
Profile Object(
[name] => D
[data] => Array (
[Real IP address] => -1
[Used proxy IP address] => -1
[HTTP Cookies] => 1
[Session Cookies] => 1
[3rd Party Cookies] => 1
[Flash Cookies] => 1
[PDF Bug] => 1
[Flash Bug] => 1
[Java Bug] => -1
[Frequent Pages] => 1
[Browsers Finger Print] => -1
[Installed Plugins] => 1
[URL] => -1
[Cached PNG] => 1
[System Fonts Detection] => 1
[Localstorage] => -1
[Geolocation] => -1
[AOLTR] => 1
[Network Information API] => -1
[Battery Status API] => -1
)
[score] => 0.74157303370787
[diff] => 0.1685393258427
[base] => 8.9
)
Wenn Debug = true, können Sie Eingabe (Sensor & Gewünscht), Anfangsgewichte, Ausgabe (Sensor, Summe, Netzwerk), Fehler, Korrektur und Endgewichte anzeigen .
+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+
| o | x1 | x2 | x3 | x4 | x5 | x6 | x7 | x8 | x9 | x10 | x11 | x12 | x13 | x14 | x15 | x16 | x17 | x18 | x19 | x20 | Bias | Yin | Y | deltaW1 | deltaW2 | deltaW3 | deltaW4 | deltaW5 | deltaW6 | deltaW7 | deltaW8 | deltaW9 | deltaW10 | deltaW11 | deltaW12 | deltaW13 | deltaW14 | deltaW15 | deltaW16 | deltaW17 | deltaW18 | deltaW19 | deltaW20 | W1 | W2 | W3 | W4 | W5 | W6 | W7 | W8 | W9 | W10 | W11 | W12 | W13 | W14 | W15 | W16 | W17 | W18 | W19 | W20 | deltaBias |
+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+
| 1 | 1 | -1 | -1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 0 | -1 | 0 | -1 | -1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 | -1 | -1 | -1 | 1 | 1 | 0 | -1 | -1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 |
| -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | -1 | -1 | 1 | -19 | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | -1 | -1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 |
| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
| 1 | 1 | -1 | -1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 19 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | -1 | -1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 |
| -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | -1 | -1 | 1 | -19 | -1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | -1 | -1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | -1 | -1 | -1 | -1 | 1 | 1 | 1 |
| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+
x1 bis x20 repräsentieren die vom Code konvertierten Features.
// Get RNA Labels
$labels = array();
$n = 1;
foreach ( $features as $k => $v ) {
$labels[$k] = "x" . $n;
$n ++;
}
Hier ist eine Online-Demo
Verwendete Klasse:
class Profile {
public $name, $data = array(), $score, $diff, $base;
function __construct($name, array $importance) {
$values = array(-1, 1); // Perception values
$this->name = $name;
foreach ($importance as $item => $point) {
// Generate Random true/false for real Items
$this->data[$item] = $values[mt_rand(0, 1)];
}
$this->base = array_sum($importance);
}
public function setScore($score, $diff) {
$this->score = $score / $this->base;
$this->diff = $diff / $this->base;
}
}
Modifizierte Perceptron-Klasse
class Perceptron {
private $w = array();
private $dw = array();
public $debug = false;
private function initialize($colums) {
// Initialize perceptron vars
for($i = 1; $i <= $colums; $i ++) {
// weighting vars
$this->w[$i] = 0;
$this->dw[$i] = 0;
}
}
function train($input, $alpha, $teta) {
$colums = count($input[0]) - 1;
$weightCache = array_fill(1, $colums, 0);
$checkpoints = array();
$keepTrainning = true;
// Initialize RNA vars
$this->initialize(count($input[0]) - 1);
$just_started = true;
$totalRun = 0;
$yin = 0;
// Trains RNA until it gets stable
while ($keepTrainning == true) {
// Sweeps each row of the input subject
foreach ($input as $row_counter => $row_data) {
// Finds out the number of columns the input has
$n_columns = count($row_data) - 1;
// Calculates Yin
$yin = 0;
for($i = 1; $i <= $n_columns; $i ++) {
$yin += $row_data["x" . $i] * $weightCache[$i];
}
// Calculates Real Output
$Y = ($yin <= 1) ? - 1 : 1;
// Sweeps columns ...
$checkpoints[$row_counter] = 0;
for($i = 1; $i <= $n_columns; $i ++) {
/** DELTAS **/
// Is it the first row?
if ($just_started == true) {
$this->dw[$i] = $weightCache[$i];
$just_started = false;
// Found desired output?
} elseif ($Y == $row_data["o"]) {
$this->dw[$i] = 0;
// Calculates Delta Ws
} else {
$this->dw[$i] = $row_data["x" . $i] * $row_data["o"];
}
/** WEIGHTS **/
// Calculate Weights
$this->w[$i] = $this->dw[$i] + $weightCache[$i];
$weightCache[$i] = $this->w[$i];
/** CHECK-POINT **/
$checkpoints[$row_counter] += $this->w[$i];
} // END - for
foreach ($this->w as $index => $w_item) {
$debug_w["W" . $index] = $w_item;
$debug_dw["deltaW" . $index] = $this->dw[$index];
}
// Special for script debugging
$debug_vars[] = array_merge($row_data, array(
"Bias" => 1,
"Yin" => $yin,
"Y" => $Y
), $debug_dw, $debug_w, array(
"deltaBias" => 1
));
} // END - foreach
// Special for script debugging
$empty_data_row = array();
for($i = 1; $i <= $n_columns; $i ++) {
$empty_data_row["x" . $i] = "--";
$empty_data_row["W" . $i] = "--";
$empty_data_row["deltaW" . $i] = "--";
}
$debug_vars[] = array_merge($empty_data_row, array(
"o" => "--",
"Bias" => "--",
"Yin" => "--",
"Y" => "--",
"deltaBias" => "--"
));
// Counts training times
$totalRun ++;
// Now checks if the RNA is stable already
$referer_value = end($checkpoints);
// if all rows match the desired output ...
$sum = array_sum($checkpoints);
$n_rows = count($checkpoints);
if ($totalRun > 1 && ($sum / $n_rows) == $referer_value) {
$keepTrainning = false;
}
} // END - while
// Prepares the final result
$result = array();
for($i = 1; $i <= $n_columns; $i ++) {
$result["w" . $i] = $this->w[$i];
}
$this->debug($this->print_html_table($debug_vars));
return $result;
} // END - train
function testCase($input, $results) {
// Sweeps input columns
$result = 0;
$i = 1;
foreach ($input as $column_value) {
// Calculates teste Y
$result += $results["w" . $i] * $column_value;
$i ++;
}
// Checks in each class the test fits
return ($result > 0) ? true : false;
} // END - test_class
// Returns the html code of a html table base on a hash array
function print_html_table($array) {
$html = "";
$inner_html = "";
$table_header_composed = false;
$table_header = array();
// Builds table contents
foreach ($array as $array_item) {
$inner_html .= "<tr>\n";
foreach ( $array_item as $array_col_label => $array_col ) {
$inner_html .= "<td>\n";
$inner_html .= $array_col;
$inner_html .= "</td>\n";
if ($table_header_composed == false) {
$table_header[] = $array_col_label;
}
}
$table_header_composed = true;
$inner_html .= "</tr>\n";
}
// Builds full table
$html = "<table border=1>\n";
$html .= "<tr>\n";
foreach ($table_header as $table_header_item) {
$html .= "<td>\n";
$html .= "<b>" . $table_header_item . "</b>";
$html .= "</td>\n";
}
$html .= "</tr>\n";
$html .= $inner_html . "</table>";
return $html;
} // END - print_html_table
// Debug function
function debug($message) {
if ($this->debug == true) {
echo "<b>DEBUG:</b> $message";
}
} // END - debug
} // END - class
Fazit
Das Identifizieren eines Benutzers ohne eindeutige Kennung ist keine einfache oder einfache Aufgabe. Dies hängt davon ab, ob eine ausreichende Menge zufälliger Daten erfasst wird, die Sie mit verschiedenen Methoden vom Benutzer erfassen können.
Selbst wenn Sie sich dafür entscheiden, kein künstliches neuronales Netzwerk zu verwenden, empfehle ich, zumindest eine einfache Wahrscheinlichkeitsmatrix mit Prioritäten und Wahrscheinlichkeiten zu verwenden - und ich hoffe, dass der Code und die Beispiele oben Ihnen genug geben, um fortzufahren.