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


132

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

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

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


5
Не совсем - по крайней мере, никаким способом, на который вы могли бы положиться, чтобы быть точным. Может быть, хеш всех трех вместе взятых, однако, если несколько человек в доме используют один и тот же браузер и ОС, это все равно не сработает. Кроме того, большинство интернет-провайдеров предоставляют динамические IP-адреса, то есть они время от времени меняются и на них также нельзя полагаться в целях идентификации.
Джон

2
Тогда вы не знаете, что такое сеансы. Ваш вариант использования - это именно то, для чего были разработаны сеансы. Сеансы не имеют ничего общего с входом в систему или аутентификацией. Ваш веб-сервер скажет клиенту отправить cookie с идентификатором сеанса. Вы идентифицируете этого клиента с помощью идентификатора сеанса, который он вам отправляет.
Man Vs Code

4
Печенье все равно будет работать? Почему вы избегаете использования куки?
Баба

2
Это действительно просто, и я использую его все время, попросить пользователя ввести имя пользователя и пароль !!!
Амит Криплани

2
Вот минимальное решение javascript (в данном случае не кросс-браузерное): github.com/carlo/jquery-browser-fingerprint Я упоминаю об этом, потому что он привел меня к мысли, что многие плагины устанавливаются кросс-браузерными по умолчанию, без любой выбор со стороны пользователя. Тщательная сортировка (что не такая уж простая задача, но все же ...) потенциально может привести к появлению ощутимого не зависящего от браузера свойства большого отпечатка пальца устройства.
hexalys

Ответы:


390

Введение

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

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

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

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

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

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

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

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

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

Искусственная нейронная сеть

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

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

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

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

+ ------------------------- + -------- + ------------ +
| Недвижимость | Вес Важность |
+ ------------------------- + -------- + ------------ +
| Реальный IP-адрес | 60 | 5 |
| Используемый IP-адрес прокси | 40 | 4 |
| HTTP Cookies | 80 | 8 |
| Файлы cookie сеанса | 80 | 6 |
| Стороннее печенье | 60 | 4 |
| Флеш печенье | 90 | 7 |
| Ошибка PDF | 20 | 1 |
| Flash Bug | 20 | 1 |
| Java Bug | 20 | 1 |
| Частые страницы | 40 | 1 |
| Браузеры отпечатков пальцев | 35 | 2 |
| Установленные плагины | 25 | 1 |
| Кэшированные изображения | 40 | 3 |
| URL | 60 | 4 |
| Определение системных шрифтов | 70 | 4 |
| Местное хранилище | 90 | 8 |
| Геолокация | 70 | 6 |
| AOLTR | 70 | 4 |
| API информации о сети | 40 | 3 |
| API состояния батареи | 20 | 1 |
+ ------------------------- + -------- + ------------ +

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

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

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

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

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

  • Храните всю возможную информацию о каждом пользователе (IP, куки и т. Д.)
  • Если результат точного соответствия, увеличьте счет на 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)

Принт_р «Д»:

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

от х1 до х20 представляют функции, преобразованные кодом.

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

Вывод

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

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


@Baba Что вы подразумеваете под «Использование BLOB-объектов» для идентификации браузера?
billmalarky


1
@Baba Как это можно использовать для отпечатка пальца в браузере? Просто проверьте, что находится в нем в любой момент времени?
billmalarky

@Baba отличная работа, я всегда пытался иметь какую-то многоуровневую стратегию для идентификации пользователя, но, как вы сказали, можно очистить кеш, изменить IP-адреса, пользователи за прокси или NAT - особенно эти люди -, удалить файлы cookie и т. Д. ... но даже при всех этих усилиях это вопрос вероятности, также, если плохой пользователь использует, например, браузер Tor , большинство, если не все упомянутые стратегии обнаружения не будут работать. Мне понравился browserleaks.com, но с Tor все вернулось неопределенным или неизвестным
Mi-Creativity

Только примечание, предназначенное только для того, чтобы «убрать пыль» с этой жемчужины публикации: Список неработающих ссылок на 07.09.17: - Implement Bayesian inference using PHP, все 3 части. - Frequency vs Probability - Joint Probability -Input (Sensor & Desired), Initial Weights, Output (Sensor, Sum, Network), Error, Correction and Final Weights
Ziezi

28

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

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

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

Больше информации:


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

Это не будет работать хорошо. Каждый браузер поддерживает сессии и куки. Используйте правильный инструмент для работы.
Человек против кода

1
@ slash197 как насчет файлового кэша? Я имею в виду использование прозрачного флеш-носителя размером 1px x 1px вместе с xml файлом, содержащим уникальный сгенерированный идентификатор внутри (xml должен быть создан один раз на сервере, прежде чем он будет загружен на локальный HD пользователя) таким образом, даже если пользователь удаляет файлы cookie или выходит из системы, у вас все еще может быть мост, используя сценарий действия метод sendAndLoad.
Mbarry

Минимум изменений повлияет на результат хеширования. например версия ударно-волнового плеера. возможное решение с локально сохраненным файлом кэша xml с сгенерированным уникальным ключом + скрытый флэш-носитель 1px x 1px (сценарий действия) в браузере, таким образом вы избавитесь от файлов cookie, проблема истечения срока действия сеанса, если это была основная проблема. у вас все еще может быть мост между вашей базой данных sql и ключом на локальном компьютере пользователя.
Мбарри

@Mbarry Я не большой поклонник флэш-памяти, но если в браузере есть надстройка, блокирующая флэш-память, такая как у меня, флэш-носитель размером 1х1 пиксель будет отключен, я не в порядке?
slash197

7

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

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

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

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


Я подумал об этом, но это самый простой способ для пользователя изменить его
slash197

1
not of the id - это хеш со ссылкой на себя. Делает его криптографически безопасным.
Джастин Александр

Кроме того, этот метод подходит, когда кто-то просматривает сайт, но как вы предлагаете обрабатывать случай, когда возвращающийся пользователь возвращается через неделю и просто вводит адрес веб-сайта без идентификатора?
slash197

@ slash197 в этом случае, почему вы не говорите пользователю, чтобы войти, что происходит, даже когда пользователь удаляет куки.
Акаш Кава

6

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

«Если пользователь получает Cookies в одном браузере и переключается на другой браузер, если у него все еще есть файл cookie Local Shared Object, он будет воспроизводиться в обоих браузерах».


Интересно, работает ли он с отключенным JavaScript? Есть ли у вас опыт?
Войткус

Это называется evercookie по причине, она будет работать, несмотря ни на что. Для них почти невозможно удалить куки.
Алексис Тайлер

Это не сработает, несмотря ни на что. Из первой строки описания: «evercookie - это API JavaScript ...». Не будет работать, если отключен javascript.
gdw2

Не нужно даже отключать JS. Ghostery и UBlock сбрасывают evercookie
opengrid

3

Вы можете сделать это с кэшированным 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: Это ваш уникальный идентификатор пользователя, который теперь кэшируется на компьютере пользователя.


Ему нужно что-то, что могло бы отслеживать пользователя «через браузеры», что здесь не работает (каждый браузер имеет свою собственную базу данных кеша).
EricLaw

Где вы это видите, его вопрос только просит: «Забыл упомянуть, что он должен быть кроссбраузерным», то есть работать в любом браузере.
Hobberwickey

Его вопрос плохо написан. I'm after device recognitionэто раздача за то, что он хочет, и он уточняет здесь: stackoverflow.com/questions/15966812/…
EricLaw 03

2

Исходя из того, что вы сказали:

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

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

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


Извините, но NIC ID легко подделать. Это точно не лучший способ.
asgs

Отпечатки в браузере @asgs, возможно, будут лучше, или, по вашему мнению, лучше всего?
Мехди Карамосли

Нет лучшего способа, и это грустно. Тем не менее, это и Browser FingerPrinting в сочетании с исследованием вероятности, которое Баба представил выше, были бы лучшими, на мой взгляд.
asgs

1

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

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


Etags не поддерживает кроссбраузерность.
slash197

1
Этаги являются частью спецификации HTTP / 1.1. Все популярные браузеры поддерживают etags, вам в значительной степени потребуется написать собственный браузер, чтобы не поддерживать заголовки ETag / If-None-Match.
Брайан МакГинити

Я не говорил, что он не поддерживает, я сказал, что он не совместим с разными браузерами. Если тег сохранен в Firefox, он недоступен в Chrome, поэтому содержимое будет загружено снова, поскольку кеша нет.
slash197

Теперь я понимаю, о чем вы говорили. Ты прав. Каждый браузер имеет собственное хранилище кешей, следовательно, разные теги.
Брайан МакГинити,

1

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

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

ссылка:

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


0

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

Это устраняет необходимость в куки и локальном хранилище.


0

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

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


0

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

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


1
вопрос здесь как?
user455318

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

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

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

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

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


Привет, добро пожаловать в переполнение стека. Пожалуйста, обратите внимание; this will require the user to willingly install the identifier.это, вероятно, не то, что имел в виду оригинальный постер (ОП).
Стефан
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.