Распознавание пользователей без cookies или локального хранилища

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

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

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

12 ответов


введение

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

  • cookies могут быть удалены
  • IP-адрес может меняться
  • Браузер Может Менять
  • кэш браузера может быть удален

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

Cookies и другие подобные инструменты

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

  1. IP-адрес
    • реальный IP-адрес
    • IP-адрес прокси (пользователи часто используют один и тот же прокси повторно)
  2. Cookies
  3. веб-ошибки (менее надежные, потому что ошибки исправляются, но все же полезны)
    • PDF ошибка
    • Флэш-Ошибка
    • Ошибка Java
  4. браузеры
    • нажмите отслеживание (многие пользователи посещают одну и ту же серию страниц при каждом посещении)
    • Браузеры Отпечатки Пальцев   - Установленные плагины (люди часто имеют различные, несколько уникальные наборы плагинов)
    • Кэшированные Рисунки (люди иногда удаляют свои куки, но оставляют кэшированные изображения)
    • Использование Blobs
    • URL-адрес(ы) (историю браузера и куки может содержать уникальный идентификатор пользователя в URL-адреса, такие как https://stackoverflow.com/users/1226894 или http://www.facebook.com/barackobama?fref=ts)
    • Обнаружение Системных Шрифтов (это малоизвестная, но часто уникальная ключевая подпись)
  5. в HTML5 & Яваскрипт
    • в HTML5 хранилище localStorage
    • HTML5 геолокации API и обратного геокодирования
    • архитектура, язык, ОС, системное время, Разрешение экрана и т. д.
    • API сетевой информации
    • состояние батареи API

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

С этим набором из случайных элементов данных для построения профиля данных, что дальше?

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

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? И которая из этих двух спичек большинство вероятно?

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

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

очевидно, a болезнь для которого мы определили более 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 |
+-------------------------+--------+------------+

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

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

для простого доказательства концепции, пожалуйста, взгляните на перцептрон. Персептрон-это модель РНК это обычно используется в приложениях распознавания образов. Есть даже старый класс PHP который реализует его отлично, но вам, вероятно, придется изменить его для ваших целей.

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

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

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

ожидание

  1. генерировать метки РНК
  2. генерировать случайных пользователей, эмулирующих базу данных
  3. создать одного неизвестного пользователя
  4. генерировать неизвестные пользовательские РНК и значения
  5. система объединит информацию о РНК и научит Персептрон!--18-->
  6. после тренировки персептрона, система будет иметь набор весов
  7. теперь вы можете проверить шаблон неизвестного пользователя, и персептрон создаст результирующий набор.
  8. хранить все положительные матчи
  9. сортировка матчей сначала по счету, а затем по разнице (как описано выше)
  10. выведите два ближайших совпадения или, если совпадений не найдено, выведите пустые результаты

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

$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, вы сможете увидеть входной сигнал (датчик & Пожеланный), начальные веса, выход (датчик, сумма, сеть), ошибка, коррекция и окончательные веса.

+----+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+------+-----+----+---------+---------+---------+---------+---------+---------+---------+---------+---------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----------+----+----+----+----+----+----+----+----+----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----------+
| 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

вывод

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

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


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

Это не безошибочно, но:

83.6% браузеров видели уникальный отпечаток пальца; среди тех, у кого включена Flash или Java, 94,2%. Это не считая печенья!

Подробнее:


вышеуказанного thumbprinting работает, но все равно может страдать colisions.

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

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

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


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

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


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

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

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

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

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

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

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


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

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

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

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

JavaScript Mac Finder


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

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


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

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

ссылки:

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


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

Это устраняет необходимость в cookies и localstorage.


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

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


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

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


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

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

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

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

пользователи не хотите, чтобы их идентифицировали (или их машины) всегда находили способ предотвратить это.