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


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

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

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

12 118

12 ответов:

введение

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

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

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

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

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

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

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

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

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

Artificial Neural Network

The 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 симптом is легче идентифицировать. На самом деле, тем более симптомы мы можем определить, более легкий и более точный наш диагноз почти уверен быть.

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

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

в качестве примера, рассмотрим такой простой таблица баллов:

+-------------------------+--------+------------+
|        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 Class который реализует его отлично, но вы, вероятно, потребуется изменить его для ваших целей.

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

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

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

ожидание

  1. генерировать метки РНК
  2. генерация случайных пользователей, эмулирующих базу данных
  3. создать одного неизвестного пользователя
  4. генерировать неизвестную пользовательскую РНК и значения
  5. система объединит информацию о РНК и научит Персептрон
  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.ex. установленные расширения, шрифты и т. д.). После этого вы можете хранить результаты хэширования, если хотите.

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

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

Подробнее:

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

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

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

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

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

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

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

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

2: создать генератор.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-адрес, который является идентификатором сетевого адаптера.

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

JavaScript Mac Finder

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

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

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

недостатком является то, что пользователь должен загрузить 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 или исправьте сетевые драйверы.

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