Introducción
Si lo entiendo correctamente, debe identificar a un usuario para el que no tiene un identificador único, por lo que desea averiguar quiénes son haciendo coincidir los datos aleatorios. No puede almacenar la identidad del usuario de manera confiable porque:
- Las cookies se pueden eliminar
- Dirección IP puede cambiar
- El navegador puede cambiar
- Se puede eliminar la caché del navegador
Un Java Applet o Com Object habría sido una solución fácil utilizando un hash de información de hardware, pero en estos días las personas son tan conscientes de la seguridad que sería difícil hacer que las personas instalen este tipo de programas en su sistema. Esto te deja atascado con el uso de cookies y otras herramientas similares.
Cookies y otras herramientas similares.
Puede considerar crear un perfil de datos y luego usar pruebas de probabilidad para identificar a un usuario probable . Se puede generar un perfil útil para esto mediante una combinación de lo siguiente:
- Dirección IP
- Dirección IP real
- Dirección IP de proxy (los usuarios a menudo usan el mismo proxy repetidamente)
- Galletas
- Errores web (menos confiables porque los errores se corrigen, pero siguen siendo útiles)
- Error de PDF
- Flash Bug
- Error de Java
- Navegadores
- Seguimiento de clics (muchos usuarios visitan la misma serie de páginas en cada visita)
- Huella digital de los navegadores: complementos instalados (las personas a menudo tienen conjuntos de complementos variados y algo únicos)
- Imágenes en caché (las personas a veces eliminan sus cookies pero dejan las imágenes en caché)
- Usando blobs
- URL (s) (el historial del navegador o las cookies pueden contener identificaciones de usuario únicas en las URL, como https://stackoverflow.com/users/1226894 o http://www.facebook.com/barackobama?fref=ts )
- Detección de fuentes del sistema (esta es una firma clave poco conocida pero a menudo única)
- HTML5 y Javascript
- HTML5 LocalStorage
- HTML5 API de geolocalización y geocodificación inversa
- Arquitectura, lenguaje del sistema operativo, hora del sistema, resolución de pantalla, etc.
- API de información de red
- API de estado de la batería
Los elementos que enumeré son, por supuesto, solo algunas maneras posibles en que un usuario puede ser identificado de manera única. Hay muchos más.
Con este conjunto de elementos de datos aleatorios para construir un perfil de datos, ¿qué sigue?
El siguiente paso es desarrollar alguna lógica difusa o, mejor aún, una red neuronal artificial (que utiliza lógica difusa). En cualquier caso, la idea es entrenar su sistema y luego combinar su entrenamiento con la Inferencia Bayesiana para aumentar la precisión de sus resultados.
La biblioteca NeuralMesh para PHP le permite generar redes neuronales artificiales. Para implementar la inferencia bayesiana, consulte los siguientes enlaces:
En este punto, puede estar pensando:
¿Por qué tanta matemática y lógica para una tarea aparentemente simple?
Básicamente, porque no es una tarea simple . Lo que está tratando de lograr es, de hecho, probabilidad pura . Por ejemplo, dados los siguientes usuarios conocidos:
User1 = A + B + C + D + G + K
User2 = C + D + I + J + K + F
Cuando reciba los siguientes datos:
B + C + E + G + F + K
La pregunta que esencialmente hace es:
¿Cuál es la probabilidad de que los datos recibidos (B + C + E + G + F + K) sean realmente Usuario1 o Usuario2? ¿Y cuál de esos dos partidos es más probable?
Para responder esta pregunta de manera efectiva, debe comprender el formato de frecuencia versus probabilidad y por qué la probabilidad conjunta podría ser un mejor enfoque. Los detalles son demasiado para entrar aquí (es por eso que le doy enlaces), pero un buen ejemplo sería una aplicación de asistente de diagnóstico médico , que utiliza una combinación de síntomas para identificar posibles enfermedades.
Piense por un momento en la serie de puntos de datos que comprenden su Perfil de datos (B + C + E + G + F + K en el ejemplo anterior) como Síntomas , y Usuarios desconocidos como Enfermedades . Al identificar la enfermedad, puede identificar aún más un tratamiento apropiado (trate a este usuario como Usuario1).
Obviamente, una enfermedad para la cual hemos identificado más de 1 síntoma es más fácil de identificar. De hecho, cuantos más síntomas podamos identificar, más fácil y preciso será nuestro diagnóstico.
¿Hay otras alternativas?
Por supuesto. Como medida alternativa, puede crear su propio algoritmo de puntuación simple y basarlo en coincidencias exactas. Esto no es tan eficiente como la probabilidad, pero puede ser más sencillo de implementar.
Como ejemplo, considere esta tabla de puntaje simple:
+ ------------------------- + -------- + ------------ +
El | Propiedad | Peso | Importancia |
+ ------------------------- + -------- + ------------ +
El | Dirección IP real | 60 5 |
El | Dirección IP de proxy utilizada | 40 | 4 |
El | Cookies HTTP | 80 8 |
El | Cookies de sesión | 80 6 |
El | Cookies de terceros | 60 4 |
El | Cookies Flash | 90 7 |
El | PDF Bug | 20 | 1 |
El | Flash Bug | 20 | 1 |
El | Error de Java | 20 | 1 |
El | Páginas frecuentes | 40 | 1 |
El | Huella digital de navegadores | 35 2 |
El | Complementos instalados | 25 1 |
El | Imágenes en caché | 40 | 3 |
El | URL | 60 4 |
El | Detección de fuentes del sistema | 70 4 |
El | Almacenamiento local | 90 8 |
El | Geolocalización | 70 6 |
El | AOLTR | 70 4 |
El | API de información de red | 40 | 3 |
El | API de estado de la batería | 20 | 1 |
+ ------------------------- + -------- + ------------ +
Para cada información que pueda reunir en una solicitud determinada, otorgue el puntaje asociado, luego use Importancia para resolver conflictos cuando los puntajes sean iguales.
Prueba de concepto
Para una simple prueba de concepto, eche un vistazo a Perceptron . Perceptron es un modelo de ARN que generalmente se usa en aplicaciones de reconocimiento de patrones. Incluso hay una antigua clase PHP que la implementa perfectamente, pero es probable que deba modificarla para sus propósitos.
A pesar de ser una gran herramienta, Perceptron aún puede devolver múltiples resultados (posibles coincidencias), por lo que usar una comparación de Puntuación y Diferencia sigue siendo útil para identificar la mejor de esas coincidencias.
Supuestos
- Almacene toda la información posible sobre cada usuario (IP, cookies, etc.)
- Cuando el resultado sea una coincidencia exacta, aumente la puntuación en 1
- Cuando el resultado no sea una coincidencia exacta, disminuya la puntuación en 1
Expectativa
- Generar etiquetas de ARN
- Generar usuarios aleatorios emulando una base de datos.
- Generar un solo usuario desconocido
- Generar ARN de usuario desconocido y valores
- El sistema fusionará la información de ARN y enseñará el Perceptrón.
- Después de entrenar el Perceptron, el sistema tendrá un conjunto de ponderaciones
- Ahora puede probar el patrón de usuario desconocido y el Perceptron producirá un conjunto de resultados.
- Almacenar todas las coincidencias positivas
- Ordene las coincidencias primero por Puntuación, luego por Diferencia (como se describió anteriormente)
- Imprime las dos coincidencias más cercanas o, si no se encuentran coincidencias, genera resultados vacíos
Código de prueba de concepto
$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 ";
}
Salida:
Possible Match D (0.7416|0.16853),C (0.5393|0.2809)
Imprimir_r de "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
)
Si Debug = true, podrá ver Entrada (Sensor y Deseado), Pesos iniciales, Salida (Sensor, Suma, Red), Error, Corrección y Pesos finales .
+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+
| 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 a x20 representan las características convertidas por el código.
// Get RNA Labels
$labels = array();
$n = 1;
foreach ( $features as $k => $v ) {
$labels[$k] = "x" . $n;
$n ++;
}
Aquí hay una demostración en línea
Clase utilizada:
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;
}
}
Clase de perceptrón modificado
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
Conclusión
Identificar a un usuario sin un Identificador único no es una tarea sencilla o sencilla. depende de la recopilación de una cantidad suficiente de Datos aleatorios que puede recopilar del usuario mediante una variedad de métodos.
Incluso si elige no usar una Red neuronal artificial, sugiero al menos usar una Matriz de probabilidad simple con prioridades y probabilidades, y espero que el código y los ejemplos proporcionados anteriormente le den suficiente para continuar.