Reconocimiento del usuario sin cookies o almacenamiento local.

132

Estoy creando una herramienta analítica y actualmente puedo obtener la dirección IP, el navegador y el sistema operativo del usuario de su agente de usuario.

Me pregunto si existe la posibilidad de detectar al mismo usuario sin usar cookies o almacenamiento local. No espero ejemplos de código aquí; solo una simple pista de dónde buscar más.

Olvidé mencionar que tendría que ser compatible con todos los navegadores si es la misma computadora / dispositivo. Básicamente, después del reconocimiento del dispositivo, no soy realmente el usuario.

slash197
fuente
55
En realidad no, al menos de ninguna manera en la que pueda confiar para ser exacto. Tal vez un hash de los tres combinados, sin embargo, si más de una persona en una casa usa el mismo navegador y sistema operativo, todavía no funcionaría. Además, la mayoría de los ISP proporcionan direcciones IP dinámicas, lo que significa que cambian de vez en cuando y tampoco se podrá confiar en ellos con fines de identificación.
Jon
2
Entonces no sabes qué son las sesiones. Su caso de uso es exactamente para lo que se diseñaron las sesiones. Las sesiones no tienen nada que ver con el inicio de sesión o la autenticación. Su servidor web le dirá a un cliente que envíe una cookie con un identificador de sesión. Identifica a ese cliente utilizando la identificación de sesión que le envían.
Man Vs Code
44
¿Las cookies seguirían funcionando? ¿Por qué evitas usar cookies?
Baba
2
¡Es realmente simple y lo uso todo el tiempo, le pido al usuario que ingrese un nombre de usuario y una contraseña!
Amit Kriplani
2
Aquí hay una solución mínima de javascript (que no es de navegador cruzado en este caso): github.com/carlo/jquery-browser-fingerprint Lo menciono, porque me llevó a la idea de que muchos complementos están instalados de manera cruzada de navegador por defecto, sin cualquier elección por parte del usuario. Clasificarlos cuidadosamente (lo cual no es una tarea pequeña, pero aún así ...) podría conducir a una propiedad tangible agnóstica del navegador de una huella digital más grande basada en el dispositivo.
hexalys

Respuestas:

389

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:

  1. Dirección IP
    • Dirección IP real
    • Dirección IP de proxy (los usuarios a menudo usan el mismo proxy repetidamente)
  2. Galletas
  3. Errores web (menos confiables porque los errores se corrigen, pero siguen siendo útiles)
    • Error de PDF
    • Flash Bug
    • Error de Java
  4. 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)
  5. 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.

Red neuronal artificial

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

  1. Generar etiquetas de ARN
  2. Generar usuarios aleatorios emulando una base de datos.
  3. Generar un solo usuario desconocido
  4. Generar ARN de usuario desconocido y valores
  5. El sistema fusionará la información de ARN y enseñará el Perceptrón.
  6. Después de entrenar el Perceptron, el sistema tendrá un conjunto de ponderaciones
  7. Ahora puede probar el patrón de usuario desconocido y el Perceptron producirá un conjunto de resultados.
  8. Almacenar todas las coincidencias positivas
  9. Ordene las coincidencias primero por Puntuación, luego por Diferencia (como se describió anteriormente)
  10. 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.

Baba
fuente
@Baba ¿Qué quieres decir con "Usar blobs" para tomar huellas digitales en un navegador?
billmalarky
1
@Baba ¿Cómo se usaría eso para tomar las huellas digitales de un navegador? ¿Solo verifica qué hay actualmente en él en un momento dado?
billmalarky
@Baba gran trabajo, siempre he intentado tener una estrategia de varios niveles para identificar a un usuario, pero como dijiste, la memoria caché se puede borrar, las direcciones IP cambiadas, los usuarios detrás de servidores proxy o NAT, especialmente esas personas , las cookies eliminadas, etc. . pero incluso con todo este esfuerzo es una cuestión de probabilidad, también si el usuario malo está usando el navegador Tor , por ejemplo, la mayoría , si no todas, las estrategias de detección mencionadas no funcionarán. Me gustó browserleaks.com pero con Tor todo volvió indefinido o desconocido
Mi-Creativity
Solo una Nota destinada únicamente a "eliminar algo de polvo" de esta joya de una publicación: Lista de enlaces rotos a partir del 07.09.17: - Implement Bayesian inference using PHP, las 3 partes. - Frequency vs Probability - Joint Probability -Input (Sensor & Desired), Initial Weights, Output (Sensor, Sum, Network), Error, Correction and Final Weights
Ziezi
28

Esta técnica (para detectar a los mismos usuarios sin cookies, o incluso sin dirección IP) se llama huella digital del navegador . Básicamente, puede rastrear la información sobre el navegador que puede: se pueden obtener mejores resultados con javascript, flash o java (por ejemplo, extensiones instaladas, fuentes, etc.). Después de eso, puede almacenar los resultados hash, si lo desea.

No es infalible, pero:

El 83,6% de los navegadores vistos tenían una huella digital única; entre aquellos con Flash o Java habilitado, 94.2%. ¡Esto no incluye cookies!

Más información:

pozs
fuente
Creo que sigue siendo la respuesta. si necesita identificar un dispositivo, solo necesita obtener esos datos - f.ex. SO, extensiones genéricas (y sus 'versiones), fuentes instaladas, etc ...
pozs
Esto no va a funcionar bien. Cada navegador admite sesiones y cookies. Use la herramienta adecuada para el trabajo.
Man Vs Code
1
@ slash197 ¿qué pasa con el caché de archivos? Me refiero a usar medios flash transparentes de 1px x 1px junto con un archivo xml que contenga una identificación única generada en su interior (el xml debe crearse una vez en el servidor antes de que se descargue al HD local del usuario) de esta manera, incluso si el usuario elimina las cookies o cierra la sesión, aún puede tener un puente usando el método de script de acción sendAndLoad.
Mbarry
El mínimo de cambio afectará el resultado del hash. por ejemplo, la versión de shock wave player. posible solución con un archivo de caché xml almacenado localmente con una clave única generada + medios flash ocultos 1px x 1px (script de acción) en el navegador, de esta manera se eliminan las cookies, el problema de caducidad de la sesión si ese era el problema principal. aún puede tener el puente entre su base de datos sql y la clave en la máquina local del usuario.
Mbarry
@Mbarry No soy muy fanático del flash, pero si en el navegador hay un complemento de bloqueo de flash como si tuviera que deshabilitarían los medios flash de 1x1 píxeles, ¿estoy loco?
slash197
7

Las huellas digitales mencionadas anteriormente funcionan, pero aún pueden sufrir colisiones.

Una forma es agregar UID a la url de cada interacción con el usuario.

http://someplace.com/12899823/user/profile

Donde cada enlace en el sitio se adapta con este modificador. Es similar a la forma en que ASP.Net solía funcionar utilizando datos FORM entre páginas.

Justin Alexander
fuente
Se me había ocurrido, pero esa es la forma más fácil para un usuario para modificarlo
slash197
1
No del ID es un hash de auto referencia. Lo hace criptográficamente seguro.
Justin Alexander
Además, este método está bien cuando alguien navega por el sitio, pero ¿cómo propone manejar el caso cuando un usuario que regresa regresa después de una semana y simplemente escribe la dirección del sitio web, sin identificación?
slash197
@ slash197 en ese caso, ¿por qué no le dice al usuario que inicie sesión, eso es lo que sucede incluso cuando el usuario elimina las cookies?
Akash Kava
6

¿Has mirado en Evercookie ? Puede o no funcionar en todos los navegadores. Un extracto de su sitio.

"Si un usuario se cocina en un navegador y cambia a otro navegador, siempre que tenga la cookie Local Shared Object, la cookie se reproducirá en ambos navegadores".

Alexis Tyler
fuente
Me pregunto si funciona con JavaScript deshabilitado. ¿Tienes alguna experiencia?
Voitcus
Se llama evercookie por una razón, funcionará sin importar qué. Es casi imposible para ellos eliminar la cookie.
Alexis Tyler
No funcionará pase lo que pase. Desde la primera línea de la descripción: 'evercookie es una API de JavaScript ...'. No funcionará si JavaScript está deshabilitado.
gdw2
No tiene que estar ni siquiera deshabilitado. Ghostery y uBlock lanzan evercookie
opengrid
3

Puede hacer esto con un png en caché, sería algo poco confiable (los diferentes navegadores se comportan de manera diferente y fallará si el usuario borra su caché), pero es una opción.

1: configure una base de datos que almacene una identificación de usuario única como una cadena hexadecimal

2: cree un archivo genUser.php (o cualquier idioma) que genere una identificación de usuario, lo almacene en la base de datos y luego cree un color verdadero .png a partir de los valores de esa cadena hexadecimal (cada píxel será de 4 bytes) y regrese eso para el navegador. Asegúrese de configurar el tipo de contenido y los encabezados de caché.

3: en HTML o JS crea una imagen como <img id='user_id' src='genUser.php' />

4: dibuja esa imagen en un lienzo ctx.drawImage(document.getElementById('user_id'), 0, 0);

5: lee los bytes de esa imagen usando ctx.getImageData, y convierte los enteros en una cadena hexadecimal.

6: Esa es su identificación de usuario única que ahora está almacenada en caché en la computadora de su usuario.

hobberwickey
fuente
Quiere algo que pueda rastrear al usuario "a través de navegadores" que no funcionará aquí (cada navegador tiene su propia base de datos de caché).
EricLaw
¿Dónde está viendo eso? Su pregunta solo pide "Olvidé mencionar que tendría que ser compatible con varios navegadores", es decir, funcionar en cualquier navegador.
hobberwickey 01 de
Su pregunta está mal escrita. I'm after device recognitiones el regalo de lo que quiere, y él elabora aquí: stackoverflow.com/questions/15966812/…
EricLaw
2

Basado en lo que has dicho:

Básicamente busco el reconocimiento del dispositivo, no el usuario

La mejor manera de hacerlo es enviar la dirección MAC, que es la ID de la NIC.

Puedes echar un vistazo a esta publicación: ¿Cómo puedo obtener el MAC y la dirección IP de un cliente conectado en PHP?

Mehdi Karamosly
fuente
Lo sentimos, pero la identificación de la NIC es fácil de suplantar. Definitivamente no es la mejor manera.
pide
La huella digital del navegador @asgs sería mejor, ¿o cuál sería la mejor manera en su opinión?
Mehdi Karamosly
No hay mejor manera, esa es la parte triste al respecto. Sin embargo, eso y Browser FingerPrinting en combinación con el estudio de probabilidad que Baba ha presentado anteriormente sería lo mejor en mi opinión.
pregunta el
1

Puedes hacerlo con etags. Aunque no estoy seguro si esto legal como un montón de demandas se presentaron.

Si advierte adecuadamente a sus usuarios o si tiene algo como un sitio web de intranet, podría estar bien.

Brian McGinity
fuente
Etags no son compatibles con el navegador cruzado.
slash197
1
Etags son parte de la especificación HTTP / 1.1. Todos los navegadores populares son compatibles con etags, prácticamente necesitará escribir su propio navegador para no admitir encabezados ETag / If-None-Match.
Brian McGinity
No dije que no lo admite, dije que no es compatible con navegadores cruzados. Si se guarda una etiqueta en Firefox, no está disponible en Chrome, por lo que el contenido se descargará nuevamente ya que no hay caché.
slash197
Ahora entiendo lo que estabas diciendo. Tienes razón. Cada navegador tiene su propio almacén de caché, de ahí diferentes etags.
Brian McGinity el
0

Ineficiente, pero puede darle los resultados deseados, sería sondear una API de su lado. Tenga un proceso en segundo plano en el lado del cliente que envíe los datos del usuario a intervalos. Necesitará un identificador de usuario para enviar a su API. Una vez que tenga eso, puede enviar cualquier información asociada a ese identificador único.

Esto elimina la necesidad de cookies y almacenamiento local.

rexposadas
fuente
0

No puedo creer, ¡ http://browserspy.dk todavía no ha sido mencionado aquí! El sitio describe muchas características (en términos de reconocimiento de patrones), que podrían usarse para construir un clasificador.

Y, por supuesto , para evaluar las características sugeriría Support Vector Machines y libsvm en particular.

Valentin Heinitz
fuente
0

Rastrearlos durante una sesión o entre sesiones?

Si su sitio es HTTPS Everywhere, puede usar el ID de sesión TLS para rastrear la sesión del usuario

Neil McGuigan
fuente
1
La pregunta aquí es cómo.
user455318
-2
  1. cree un complemento ficticio multiplataforma (nsapi) y genere un nombre único para el nombre o la versión del complemento cuando el usuario lo descargue (por ejemplo, después de iniciar sesión).
  2. Proporcionar un instalador para el complemento / instalarlo según la política

esto requerirá que el usuario instale voluntariamente el identificador.

una vez que se instala el complemento, la huella digital de cualquier navegador (complemento habilitado) contendrá este complemento específico. Para devolver la información a un servidor, se necesita un algoritmo para detectar efectivamente el complemento en el lado del cliente; de ​​lo contrario, IE y Firefox> = 28 usuarios necesitarán una tabla de posibles identificaciones válidas.

Esto requiere una inversión relativamente alta en una tecnología que probablemente será cerrada por los proveedores de navegadores. Cuando pueda convencer a sus usuarios para que instalen un complemento, también puede haber opciones como instalar un proxy local , usar vpn o parchear los controladores de red.

Los usuarios que no desean ser identificados (o sus máquinas) siempre encontrarán una manera de evitarlo.

aec8adaikaeNg6hey2oof8otai9quo
fuente
Hola, bienvenido a stack overflow. Tenga en cuenta; this will require the user to willingly install the identifier.probablemente no sea lo que significaba el póster original (OP).
Stefan