web-dev-qa-db-fra.com

Reconnaissance de l'utilisateur sans cookies ni stockage local

Je construis un outil d'analyse et je peux actuellement obtenir l'adresse IP de l'utilisateur, son navigateur et son système d'exploitation auprès de son agent utilisateur.

Je me demande s'il est possible de détecter le même utilisateur sans utiliser de cookies ou de stockage local? Je ne m'attends pas à des exemples de code ici; juste un indice simple de l'endroit où chercher plus loin.

J'ai oublié de mentionner qu'il devrait être compatible avec plusieurs navigateurs s'il s'agit du même ordinateur/périphérique. Fondamentalement, je suis après la reconnaissance de l'appareil pas vraiment l'utilisateur.

124
slash197

Introduction

Si je vous ai bien compris, vous devez identifier un utilisateur pour lequel vous ne possédez pas d'identificateur unique. Vous devez donc déterminer qui il est en mettant en correspondance des données aléatoires. Vous ne pouvez pas stocker l'identité de l'utilisateur de manière fiable pour les raisons suivantes:

  • Les cookies peuvent être supprimés
  • Adresse IP peut changer
  • Le navigateur peut changer
  • Le cache du navigateur peut être supprimé

A Java Applet ou Com Object aurait été une solution facile en utilisant un hachage d'informations matérielles, mais de nos jours, les utilisateurs sont tellement conscients de la sécurité qu'il serait difficile de les amener à installer ce type de logiciel. programmes sur leur système, ce qui vous oblige à utiliser des cookies et d’autres outils similaires.

Cookies et autres outils similaires

Vous pouvez envisager de créer un profil de données, puis d’utiliser des tests de probabilité pour identifier un utilisateur probable . Un profil utile pour cela peut être généré par une combinaison des éléments suivants:

  1. Adresse IP
    • Adresse IP réelle
    • Adresse IP du proxy (les utilisateurs utilisent souvent le même proxy à plusieurs reprises)
  2. Biscuits
  3. Bugs Web (moins fiable car les bugs sont corrigés, mais toujours utile)
    • Bug PDF
    • Flash Bug
    • Bug Java
  4. Navigateurs
    • Suivi des clics (de nombreux utilisateurs visitent la même série de pages à chaque visite)
    • Finger Print des navigateurs - Plugins installés (les utilisateurs disposent souvent d’ensembles de plugins variés et plutôt uniques)
    • Images en cache (les gens suppriment parfois leurs cookies mais laissent des images en cache)
    • Utiliser des blobs
    • URL (s) (l'historique du navigateur ou les cookies peuvent contenir des identifiants d'utilisateur uniques, tels que https://stackoverflow.com/users/1226894 ou http: //www.facebook. com/barackobama? fref = ts )
    • Détection de polices système (c'est une signature de clé peu connue mais souvent unique)
  5. HTML5 Javascript
    • HTML5 LocalStorage
    • API de géolocalisation HTML5 et géocodage inversé
    • Architecture, langue du système d'exploitation, heure du système, résolution de l'écran, etc.
    • API d'informations réseau
    • API d'état de la batterie

Les éléments que j'ai énumérés ne sont, bien sûr, que quelques moyens d'identifier un utilisateur de manière unique. Il y en a beaucoup plus.

Avec ce jeu d'éléments de données aléatoires pour créer un profil de données, quelle est la suite?

La prochaine étape consiste à développer un logique floue , ou, mieux encore, un réseau de neurones artificiels (qui utilise la logique floue). Dans les deux cas, l’idée est de former votre système, puis de combiner sa formation avec Bayesian Inference pour augmenter la précision de vos résultats.

Artificial Neural Network

La bibliothèque NeuralMesh pour PHP vous permet de générer des réseaux de neurones artificiels. Pour implémenter Bayesian Inference, consultez les liens suivants:

À ce stade, vous pensez peut-être:

Pourquoi tant de math et de logique pour une tâche apparemment simple?

Fondamentalement, parce que ce n'est pas une tâche simple . Ce que vous essayez d’atteindre, c’est en fait la probabilité pure . Par exemple, étant donné les utilisateurs connus suivants:

User1 = A + B + C + D + G + K
User2 = C + D + I + J + K + F

Lorsque vous recevez les données suivantes:

B + C + E + G + F + K

La question que vous posez essentiellement est la suivante:

Quelle est la probabilité que les données reçues (B + C + E + G + F + K) soient réellement User1 ou User2? Et laquelle de ces deux correspondances est la plus probable?

Afin de répondre efficacement à cette question, vous devez comprendre Format de la fréquence par rapport aux probabilités et pourquoi Probabilité conjointe pourrait être une meilleure approche. Les détails sont trop compliqués pour entrer ici (c'est pourquoi je vous donne des liens), mais un bon exemple serait un diagnostic médical Wizard Application , qui utilise une combinaison de symptômes pour identifier les maladies possibles.

Pensez un instant à la série de points de données qui composent votre profil de données (B + C + E + G + F + K dans l'exemple ci-dessus) en tant que Symptômes et utilisateurs inconnus. comme Maladies . En identifiant la maladie, vous pouvez en outre identifier un traitement approprié (traiter cet utilisateur comme un utilisateur1).

Évidemment, une maladie pour laquelle nous avons identifié plus de 1 symptôme est plus facile à identifier. En fait, plus nous pouvons identifier de symptômes , plus notre diagnostic sera facile et précis.

Y a-t-il d'autres alternatives?

Bien sûr. À titre de mesure alternative, vous pouvez créer votre propre algorithme de scoring simple et le baser sur des correspondances exactes. Ce n'est pas aussi efficace que la probabilité, mais peut être plus simple à mettre en œuvre.

A titre d'exemple, considérons ce tableau de score simple:

 + ------------------------- + -------- + --------- --- + 
 | Propriété | Poids | Importance | 
 + ------------------------- + -------- + ------- ----- + 
 | Adresse IP réelle | 60 | 5 | 
 | Adresse IP proxy utilisée | 40 | 4 | 
 | Cookies HTTP | 80 | 8 | 
 | Cookies de session | 80 | 6 | 
 | Cookies de tiers | 60 | 4 | 
 | Cookies Flash | 90 | 7 | 
 | PDF Bug | 20 | 1 | 
 | Bug Flash | 20 | 1 | 
 | Java Bug | 20 | 1 | 
 | Pages fréquentes | 40 | 1 | 
 | Empreintes digitales de navigateurs | 35 | 2 | 
 | Plugins installés | 25 | 1 | 
 | Images en cache | 40 | 3 | 
 | URL | 60 | 4 | 
 | Détection de polices système | 70 | 4 | 
 | Stockage local | 90 | 8 | 
 | Géolocalisation | 70 | 6 | 
 | AOLTR | 70 | 4 | 
 | API d'informations réseau | 40 | 3 | 
 | API d'état de la batterie | 20 | 1 | 
 + ------------------------- + -------- + ------------ + 

Attribuez le score associé à chaque information que vous pouvez recueillir sur une demande donnée, puis utilisez Importance pour résoudre les conflits lorsque les scores sont identiques.

Preuve de concept

Pour une simple validation de principe, veuillez jeter un oeil à Perceptron . Le perceptron est un modèle d'ARN généralement utilisé dans les applications de reconnaissance de formes. Il existe même un vieux PHP Class qui l'implémente parfaitement, mais vous devrez probablement le modifier pour vos besoins.

Bien que Perceptron soit un excellent outil, il peut toujours renvoyer plusieurs résultats (correspondances possibles). Il est donc utile d’utiliser une comparaison Score et Différence pour identifier le meilleur meilleur de ces correspondances.

Hypothèses

  • Stocker toutes les informations possibles sur chaque utilisateur (IP, cookies, etc.)
  • Si le résultat est une correspondance exacte, augmenter le score de 1
  • Si le résultat n'est pas une correspondance exacte, diminuez le score de 1

Attente

  1. Générer des étiquettes d'ARN
  2. Générer des utilisateurs aléatoires en émulant une base de données
  3. Générer un seul utilisateur inconnu
  4. Générer un ARN et des valeurs d'utilisateur inconnu
  5. Le système fusionnera les informations sur l'ARN et enseignera le Perceptron
  6. Après la formation du Perceptron, le système aura un ensemble de pondérations
  7. Vous pouvez maintenant tester le motif de l'utilisateur inconnu et Perceptron produira un ensemble de résultats.
  8. Stocker toutes les correspondances positives
  9. Triez les correspondances d'abord par score, puis par différence (comme décrit ci-dessus)
  10. Affiche les deux correspondances les plus proches ou, si aucune correspondance n'est trouvée, les résultats vides

Code de validation de principe

$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 ";
}

Sortie:

Possible Match D (0.7416|0.16853),C (0.5393|0.2809)

Print_r of "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, vous pourrez voir entrée (capteur et souhaité), poids initiaux, sortie (capteur, somme, réseau), erreur, correction et poids finaux .

+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+
| 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 à x20 représentent les entités converties par le code.

// Get RNA Labels
$labels = array();
$n = 1;
foreach ( $features as $k => $v ) {
    $labels[$k] = "x" . $n;
    $n ++;
}

Voici un démo en ligne

Classe utilisée:

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;
    }
}

Classe de Perceptron modifiée

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

Conclusion

Identifier un utilisateur sans identifiant unique n'est pas une tâche simple ou directe. cela dépend de la collecte d'une quantité suffisante de données aléatoires que vous pouvez collecter auprès de l'utilisateur par diverses méthodes.

Même si vous choisissez de ne pas utiliser de réseau de neurones artificiels, je suggère au moins d'utiliser une matrice de probabilité simple avec des priorités et des probabilités - et j'espère que le code et les exemples fournis ci-dessus vous en donneront suffisamment pour continuer.

375
Baba

Cette technique (pour détecter les mêmes utilisateurs sans cookies - ou même sans adresse IP) est appelée empreinte du navigateur . Fondamentalement, vous explorez autant que possible les informations relatives au navigateur - vous pouvez obtenir de meilleurs résultats avec javascript, flash ou Java (par exemple, les extensions installées, les polices, etc.). peut stocker les résultats hachés, si vous voulez.

Ce n'est pas infaillible, mais:

83,6% des navigateurs consultés avaient une empreinte digitale unique; parmi ceux avec Flash ou Java activé, 94,2%. Cela n'inclut pas les cookies!

Plus d'informations:

27
pozs

Avez-vous examiné Evercookie ? Cela peut ou peut ne pas fonctionner avec les navigateurs. Un extrait de leur site.

"Si un utilisateur est enregistré dans un navigateur et passe à un autre, tant qu'il dispose du cookie Local Shared Object, le cookie est reproduit dans les deux navigateurs."

5
Alexis Tyler

Les empreintes de pouce mentionnées ci-dessus fonctionnent, mais peuvent tout de même souffrir de collisions.

Une solution consiste à ajouter l'UID à l'URL de chaque interaction avec l'utilisateur.

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

Où chaque lien du site est adapté avec ce modificateur. Cela ressemble à la façon dont ASP.Net utilisait les données FORM entre les pages.

5
Justin Alexander

Vous pourriez faire cela avec un png en cache, ce serait quelque peu peu fiable (différents navigateurs se comportent différemment, et cela échouera si l'utilisateur efface son cache), mais c'est une option.

1: configurer une base de données qui stocke un ID utilisateur unique sous forme de chaîne hexadécimale

2: créez un fichier genUser.php (ou n’importe quelle langue) qui génère un ID utilisateur, le stocke dans la base de données, puis crée une vraie couleur .png à partir des valeurs de cette chaîne hexadécimale (chaque pixel sera de 4 octets), puis retourne cela au navigateur. Veillez à définir les en-têtes de type de contenu et de cache.

3: dans HTML ou JS, créez une image du type <img id='user_id' src='genUser.php' />

4: dessine cette image sur une toile ctx.drawImage(document.getElementById('user_id'), 0, 0);

5: lisez les octets de cette image en utilisant ctx.getImageData Et convertissez les entiers en chaîne hexadécimale.

6: C'est votre identifiant utilisateur unique qui est maintenant mis en cache sur l'ordinateur de vos utilisateurs.

2
hobberwickey

Sur la base de ce que vous avez dit:

Fondamentalement, je suis après la reconnaissance de l'appareil pas vraiment l'utilisateur

La meilleure façon de le faire est d’envoyer l’adresse MAC qui est le NIC ID.

Vous pouvez jeter un oeil à ce post: Comment puis-je obtenir le MAC et l'adresse IP d'un client connecté en PHP?

JavaScript Mac Finder

2
Mehdi Karamosly

Vous pouvez éventuellement créer un blob pour stocker un identifiant de périphérique ...

l'inconvénient est que l'utilisateur doit télécharger le blob ( vous pouvez forcer le téléchargement ), car le navigateur ne peut pas accéder au système de fichiers pour enregistrer directement le fichier.

référence:

https://www.inkling.com/read/javascript-definitive-guide-david-flanagan-6th/chapter-22/blobs

1
DanielDMO

Vous pouvez le faire avec etags. Bien que je ne sois pas sûr si cette action légale a été entamée.

Si vous prévenez correctement vos utilisateurs ou si vous avez quelque chose comme un site intranet, tout ira bien.

1
Brian McGinity

Je ne peux pas croire, http://browserspy.dk n'a toujours pas été mentionné ici! Le site décrit de nombreuses fonctionnalités (en termes de reconnaissance de modèle), qui pourraient être utilisées pour créer un classificateur.

Et bien sûr, pour évaluer les fonctionnalités, je suggérerais Support Vector Machines et libsvm en particulier.

0
Valentin Heinitz

Les suivre au cours d'une session ou d'une session à l'autre?

Si votre site est HTTPS Everywhere, vous pouvez utiliser l'ID de session TLS pour suivre la session de l'utilisateur.

0
Neil McGuigan

Inefficace, mais peut vous donner les résultats souhaités, serait de sonder une API de votre côté. Avoir un processus en arrière-plan côté client qui envoie les données utilisateur à un intervalle. Vous aurez besoin d'un identifiant d'utilisateur à envoyer à votre API. Une fois que vous avez cela, vous pouvez envoyer toutes les informations associées à cet identifiant unique.

Cela supprime le besoin de cookies et de stockage local.

0
rexposadas