Пользовательское распознавание без файлов cookie или локального хранилища

Я создаю аналитический инструмент, и теперь я могу получить IP-адрес пользователя, браузер и операционную систему от своего пользовательского агента.

Мне интересно, есть ли возможность обнаружить одного и того же пользователя без использования файлов cookie или локального хранилища? Я не ожидаю примеров кода здесь; просто простой намек на то, где искать дальше.

Забыл упомянуть, что он должен быть совместим с несколькими браузерами, если это тот же компьютер/устройство. В принципе, я не признаю распознавание устройств.

Ответ 1

Введение

Если вы правильно поняли, вам нужно определить пользователя, для которого у вас нет уникального идентификатора, поэтому вы хотите выяснить, кто они, сопоставляя случайные данные. Вы не можете надежно хранить идентификатор пользователя, потому что:

  • Файлы cookie могут быть удалены
  • IP-адрес Можно изменить
  • Браузер может изменить
  • Браузер может быть удален

Апплет Java или Com Object был бы простым решением с использованием хеш-информации об оборудовании, но в наши дни люди настолько осведомлены о безопасности, что было бы сложно заставить людей устанавливать эти программы в своей системе. Это оставляет вас застрявшим с использованием Cookies и других подобных инструментов.

Файлы cookie и другие аналогичные инструменты

Вы можете рассмотреть вопрос о создании профиля данных, а затем использовать тесты вероятности для определения Вероятного пользователя. Профиль, полезный для этого, может быть сгенерирован некоторой комбинацией следующего:

  • IP-адрес
    • Реальный IP-адрес
    • IP-адрес прокси (пользователи часто используют один и тот же прокси-сервер)
  • Печенье
  • Веб-ошибки (менее надежны, потому что ошибки исправляются, но все же полезны)
    • Ошибка PDF
    • Ошибка Flash
    • Ошибка Java
  • Браузеры
    • Отслеживание кликов (многие пользователи посещают ту же серию страниц при каждом посещении)
    • Браузеры Finger Print - Установленные плагины (люди часто менялись, несколько уникальных наборов плагинов).
    • Кэш файлы (люди иногда удаляют свои файлы cookie, но оставляют кешированные изображения)
    • Использование Blobs
    • URL (истории браузера или файлы cookie могут содержать уникальный идентификатор пользователя в URL-адресах, например https://stackoverflow.com/users/1226894 или <а2 > )
    • Обнаружение системных шрифтов (это малоизвестная, но часто уникальная подпись ключа)
  • HTML5 и Javascript
    • HTML5 LocalStorage
    • API-интерфейс геолокации HTML5 и обратное геокодирование
    • Архитектура, язык ОС, системное время, разрешение экрана и т.д.
    • Сетевой информационный API
    • API состояния батареи

Элементы, перечисленные мной, конечно, всего лишь несколько возможных способов идентификации пользователя однозначно. Есть еще много.

С помощью этого набора элементов Random Data для создания профиля данных, из следующего:

Следующим шагом будет разработка Fuzzy Logic или, еще лучше, Искусственная нейронная сеть (которая использует нечеткую логику). В любом случае, идея состоит в том, чтобы обучить вашу систему, а затем объединить ее обучение с Bayesian Inference, чтобы повысить точность ваших результатов.

Artificial Neural Network

Библиотека NeuralMesh для PHP позволяет создавать искусственные нейронные сети. Чтобы реализовать байесовский вывод, проверьте следующие ссылки:

На этом этапе вы можете подумать:

Почему так много математики и логики для кажущейся простой задачи?

В принципе, потому что это непростая задача. То, что вы пытаетесь достичь, - это, по сути, Чистая Вероятность. Например, при использовании следующих известных пользователей:

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

Когда вы получите следующие данные:

B + C + E + G + F + K

Вопрос, который вы, по сути, задаете, следующий:

Какова вероятность того, что полученные данные (B + C + E + G + F + K) на самом деле являются User1 или User2? И какой из этих двух матчей наиболее вероятен?

Чтобы эффективно ответить на этот вопрос, вам нужно понять Частота против формата вероятности и почему Совместная вероятность может быть лучшим подходом. Детали слишком много, чтобы попасть сюда (вот почему я даю вам ссылки), но хорошим примером может служить Приложение мастера диагностики диагнозов, который использует комбинацию симптомов для выявления возможных заболеваний.

Подумайте о моменте серии точек данных, которые содержат ваш профиль данных (B + C + E + G + F + K в приведенном выше примере) как симптомы, а также неизвестные пользователи как болезни. Выявив заболевание, вы можете дополнительно определить подходящее лечение (лечить этого пользователя как User1).

Очевидно, что болезнь, для которой мы идентифицировали более 1 Симптома, легче идентифицировать. Фактически, чем больше симптомов мы можем идентифицировать, тем легче и точнее наш диагноз, почти наверняка будет.

Есть ли другие альтернативы?

Конечно. В качестве альтернативной меры вы можете создать свой собственный простой алгоритм подсчета очков и основывать его на точном совпадении. Это не так эффективно, как вероятность, но может быть проще для вас.

В качестве примера рассмотрим эту простую таблицу баллов:

+-------------------------+--------+------------+
|        Property         | Weight | Importance |
+-------------------------+--------+------------+
| Real IP address         |     60 |          5 |
| Used proxy IP address   |     40 |          4 |
| HTTP Cookies            |     80 |          8 |
| Session Cookies         |     80 |          6 |
| 3rd Party Cookies       |     60 |          4 |
| Flash Cookies           |     90 |          7 |
| PDF Bug                 |     20 |          1 |
| Flash Bug               |     20 |          1 |
| Java Bug                |     20 |          1 |
| Frequent Pages          |     40 |          1 |
| Browsers Finger Print   |     35 |          2 |
| Installed Plugins       |     25 |          1 |
| Cached Images           |     40 |          3 |
| URL                     |     60 |          4 |
| System Fonts Detection  |     70 |          4 |
| Localstorage            |     90 |          8 |
| Geolocation             |     70 |          6 |
| AOLTR                   |     70 |          4 |
| Network Information API |     40 |          3 |
| Battery Status API      |     20 |          1 |
+-------------------------+--------+------------+

Для каждой части информации, которую вы можете собрать по заданному запросу, присудите соответствующий балл, затем используйте значение "Важность" для разрешения конфликтов, если баллы одинаковы.

Доказательство концепции

Для простого доказательства концепции, пожалуйста, взгляните на Perceptron. Перцептрон представляет собой Модель РНК, которая обычно используется в приложениях распознавания образов. Существует даже старый класс PHP, который прекрасно его реализует, но вам, скорее всего, придется его модифицировать для своих целей.

Несмотря на то, что Perceptron является отличным инструментом, он может возвращать несколько результатов (возможные совпадения), поэтому использование сравнения по шкале и разнице по-прежнему полезно для определения наилучшего из этих совпадений.

Предположения

  • Храните всю возможную информацию о каждом пользователе (IP, файлы cookie и т.д.).
  • Где результат - точное совпадение, увеличьте оценку на 1
  • Если результат не является точным, уменьшите оценку на 1

Ожидание

  • Создание меток РНК
  • Генерация случайных пользователей, имитирующих базу данных
  • Создание единого Неизвестного пользователя
  • Генерация неизвестной пользовательской РНК и значений
  • Система объединит информацию РНК и научит Perceptron
  • После обучения Perceptron система будет иметь набор весов
  • Теперь вы можете протестировать шаблон Неизвестного пользователя, и Perceptron создаст результирующий набор.
  • Сохранить все положительные совпадения
  • Сортировка совпадений сначала по счету, затем по разности (как описано выше)
  • Выведите два ближайших совпадения или, если совпадений не найдено, выведите пустые результаты

Код для доказательства концепции

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

Выход:

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

Print_r из "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
)

Если Debug = true, вы сможете увидеть Input (Sensor and Desired), Initial Weight, Output (Sensor, Sum, Network), Error, Correction и итоговые веса.

+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+
| 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 представляют функции, преобразованные кодом.

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

Вот онлайн-демонстрация

Используемый класс:

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

Измененный класс перцептронов

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

Заключение

Идентификация пользователя без уникального идентификатора не является прямой или простой задачей. это зависит от сбора достаточного количества случайных данных, которые вы можете собирать у пользователя различными способами.

Даже если вы решите не использовать искусственную нейронную сеть, я предлагаю по крайней мере использовать простую матрицу вероятностей с приоритетами и вероятностями - и я надеюсь, что приведенный выше код и примеры дают вам достаточно возможностей для продолжения.

Ответ 2

Этот метод (для обнаружения тех же пользователей без куки файлов или даже без IP-адреса) называется отпечатком браузера. В основном вы сканируете как информацию о браузере, как можете - лучшие результаты могут быть достигнуты с помощью javascript, flash или java (f.ex. установлены расширения, шрифты и т.д.). После этого вы можете сохранить результаты хэширования, если хотите.

Это не непогрешимо, но:

83,6% просмотренных браузеров имели уникальный отпечаток; среди тех, кто поддерживает Flash или Java, - 94,2%. Это не включает файлы cookie!

Дополнительная информация:

Ответ 3

Вышеупомянутые операции с печатью, но могут по-прежнему страдать от коллизий.

Один из способов - добавить UID к URL-адресу каждого взаимодействия с пользователем.

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

Где каждая ссылка на сайте адаптируется с этим модификатором. Это похоже на способ использования ASP.Net с использованием данных FORM между страницами.

Ответ 4

Вы просмотрели Evercookie? Он может работать или не работать в браузерах. Экстракт со своего сайта.

"Если пользователь загружается в одном браузере и переключается на другой браузер,   пока они все еще имеют файл cookie локального общего объекта, cookie   будет воспроизводиться в обоих браузерах."

Ответ 5

Вы можете сделать это с помощью кэшированного png, это будет несколько ненадежным (разные браузеры ведут себя по-другому, и это не удастся, если пользователь очистит их кеш), но это вариант.

1: настройте базу данных, в которой хранится уникальный идентификатор пользователя в виде шестнадцатеричной строки

2: создайте файл genUser.php(или любой другой язык), который генерирует идентификатор пользователя, сохраняет его в БД и затем создает истинный цвет .png из значений этой шестнадцатеричной строки (каждый пиксель будет 4 байта ) и верните это в браузер. Обязательно установите заголовки содержимого и кеширования.

3: в HTML или JS создайте изображение типа <img id='user_id' src='genUser.php' />

4: нарисуйте это изображение на холсте ctx.drawImage(document.getElementById('user_id'), 0, 0);

5: прочитайте байты этого изображения с помощью ctx.getImageData и преобразуйте целые числа в шестую строку.

6: Это ваш уникальный идентификатор пользователя, который теперь кэшируется на вашем компьютере пользователя.

Ответ 6

Основываясь на том, что вы сказали:

В основном я получаю признание устройства не на самом деле

Лучший способ сделать это - отправить MAC-адрес, который является идентификатором NIC.

Вы можете посмотреть этот пост: Как я могу получить MAC и IP-адрес подключенного клиента в PHP?

JavaScript Mac Finder

Ответ 7

Вы можете сделать это с помощью etags. Хотя я не уверен, что этот законный закон был подан в суде.

Если вы правильно предупреждаете своих пользователей или у вас есть что-то вроде веб-сайта интрасети, возможно, все в порядке.

Ответ 8

Вы можете создать blob для хранения идентификатора устройства...

недостатком является то, что пользователю нужно загрузить blob (вы можете принудительно загрузить), так как браузер не может получить доступ к файловой системе, чтобы напрямую сохранить файл.

ссылка:

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

Ответ 9

Неэффективен, но может дать вам желаемые результаты, это будет опрос API на вашей стороне. Имейте фоновый процесс на стороне клиента, который отправляет пользовательские данные с интервалом. Вам потребуется идентификатор пользователя для отправки в ваш API. После этого вы можете отправить любую информацию, связанную с этим уникальным идентификатором.

Это устраняет необходимость в файлах cookie и localstorage.

Ответ 10

Не могу поверить, http://browserspy.dk до сих пор не упоминается! На сайте описаны многие функции (с точки зрения распознавания образов), которые могут быть использованы для создания классификатора.

И для того, чтобы оценить функции, которые я предлагаю, поддерживайте векторные машины и libsvm в частности.

Ответ 11

Отслеживать их во время сеанса или между сеансами?

Если ваш сайт HTTPS Everywhere, вы можете использовать идентификатор сеанса TLS для отслеживания сеанса пользователя

Ответ 12

  • создать плагин подплатной платформы (nsapi) и создать уникальное имя для имени или версии плагина, когда пользователь загрузит его (например, после входа в систему).
  • предоставить установщик для плагина/установить его на политику

это потребует от пользователя добровольной установки идентификатора.

После установки плагина fingerprint любого (подключенного к плагину) браузера будет содержать этот конкретный плагин. Чтобы вернуть информацию на сервер, необходим алгоритм для эффективного обнаружения плагина на стороне клиента, в противном случае IE и Firefox >= 28 пользователям потребуется таблица возможных действительных идентификаторов.

Для этого требуется относительно высокая инвестиция в технологию, которая, вероятно, будет отключена поставщиками браузеров. Когда вы сможете убедить своих пользователей в установке плагина, также могут быть такие опции, как установка локального прокси, использование vpn или исправление сетевых драйверов.

Пользователи, которые не хотят быть идентифицированными (или их машины), всегда найдут способ предотвратить его.