Riconoscimento dell'utente senza cookie o archiviazione locale


132

Sto creando uno strumento analitico e attualmente posso ottenere l'indirizzo IP dell'utente, il browser e il sistema operativo dal loro agente utente.

Mi chiedo se esiste la possibilità di rilevare lo stesso utente senza utilizzare i cookie o l'archiviazione locale? Non mi aspetto esempi di codice qui; solo un semplice suggerimento su dove guardare oltre.

Hai dimenticato di dire che dovrebbe essere compatibile con più browser se è lo stesso computer / dispositivo. Fondamentalmente sto cercando il riconoscimento del dispositivo non proprio l'utente.


5
Non proprio - almeno non in alcun modo su cui fare affidamento per essere precisi. Forse un hash di tutti e tre combinati, tuttavia se più di una persona in una casa utilizza lo stesso browser e lo stesso sistema operativo, non funzionerebbe comunque. Inoltre, la maggior parte degli ISP fornisce indirizzi IP dinamici, il che significa che cambiano ogni tanto e che non potranno neppure essere utilizzati per scopi di identificazione.
Jon,

2
Quindi non sai quali sono le sessioni. Il tuo caso d'uso è esattamente quello per cui sono state progettate le sessioni. Le sessioni non hanno nulla a che fare con l'accesso o l'autenticazione. Il tuo server web dirà a un client di inviare un cookie con un identificatore di sessione. Identifichi quel client usando l'id di sessione che ti inviano.
Man Vs Code

4
I cookie funzionerebbero ancora? Perché stai evitando di usare i cookie?
Baba,

2
È davvero semplice e lo uso sempre, chiedo all'utente di inserire un nome utente e una password !!!
Amit Kriplani,

2
Ecco una soluzione javascript minima (in questo caso non cross-browser): github.com/carlo/jquery-browser-fingerprint Ne parlo, perché mi ha portato all'idea che molti plug-in sono installati cross-browser per impostazione predefinita, senza qualsiasi scelta da parte dell'utente. L'ordinamento accurato (che non è un compito piccolo, ma comunque ...) potrebbe potenzialmente portare a una proprietà tangibile al browser di un'impronta digitale più grande basata su dispositivo.
hexalys,

Risposte:


389

introduzione

Se ti capisco correttamente, devi identificare un utente per il quale non hai un identificatore univoco, quindi vuoi capire chi sono abbinando i dati casuali. Non è possibile memorizzare l'identità dell'utente in modo affidabile perché:

  • I cookie possono essere cancellati
  • L'indirizzo IP può cambiare
  • Il browser può cambiare
  • La cache del browser potrebbe essere eliminata

Un'applet Java o un oggetto Com sarebbe stata una soluzione semplice utilizzando un hash di informazioni sull'hardware, ma oggigiorno le persone sono così consapevoli della sicurezza che sarebbe difficile indurre le persone a installare questo tipo di programmi sul proprio sistema. Questo ti lascia bloccato con l'utilizzo di cookie e altri strumenti simili.

Cookie e altri strumenti simili

Potresti prendere in considerazione la creazione di un profilo dati, quindi utilizzare i test di probabilità per identificare un probabile utente . Un profilo utile per questo può essere generato da una combinazione dei seguenti elementi:

  1. Indirizzo IP
    • Indirizzo IP reale
    • Indirizzo IP proxy (gli utenti usano spesso ripetutamente lo stesso proxy)
  2. Biscotti
  3. Bug Web (meno affidabili perché i bug vengono corretti, ma comunque utili)
    • Bug PDF
    • Bug flash
    • Bug Java
  4. browser
    • Tracciamento dei clic (molti utenti visitano la stessa serie di pagine per ogni visita)
    • Browser Finger Print - Plugin installati (le persone hanno spesso set di plug-in vari, piuttosto unici)
    • Immagini memorizzate nella cache (le persone a volte eliminano i cookie ma lasciano immagini memorizzate nella cache)
    • Usando BLOB
    • URL (la cronologia del browser o i cookie possono contenere ID utente univoci negli URL, come https://stackoverflow.com/users/1226894 o http://www.facebook.com/barackobama?fref=ts )
    • Rilevamento caratteri di sistema (si tratta di una firma chiave poco conosciuta ma spesso unica)
  5. HTML5 e Javascript
    • HTML5 LocalStorage
    • API di geolocalizzazione HTML5 e geocodifica inversa
    • Architettura, lingua del sistema operativo, ora del sistema, risoluzione dello schermo, ecc.
    • API delle informazioni di rete
    • API di stato della batteria

Gli elementi che ho elencato sono, ovviamente, solo alcuni dei modi in cui un utente può essere identificato in modo univoco. Ce ne sono molti altri.

Con questo set di elementi di dati casuali da cui creare un profilo dati, quali sono le prospettive?

Il prossimo passo è sviluppare una Fuzzy Logic , o, meglio ancora, una rete neurale artificiale (che usa la logica fuzzy). In entrambi i casi, l'idea è quella di addestrare il sistema e quindi combinare la sua formazione con l'inferenza bayesiana per aumentare l'accuratezza dei risultati.

Rete neurale artificiale

La libreria NeuralMesh per PHP ti consente di generare reti neurali artificiali. Per implementare l'inferenza bayesiana, controlla i seguenti collegamenti:

A questo punto, potresti pensare:

Perché così tanta matematica e logica per un compito apparentemente semplice?

Fondamentalmente, perché non è un compito semplice . Ciò che stai cercando di ottenere è, in effetti, Pura Probabilità . Ad esempio, dati i seguenti utenti noti:

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

Quando ricevi i seguenti dati:

B + C + E + G + F + K

La domanda che si pone essenzialmente è:

Qual è la probabilità che i dati ricevuti (B + C + E + G + F + K) siano effettivamente Utente1 o Utente2? E quale di queste due partite è più probabile?

Per rispondere efficacemente a questa domanda, è necessario comprendere la frequenza rispetto al formato di probabilità e perché la probabilità congiunta potrebbe essere un approccio migliore. I dettagli sono troppi per entrare qui (motivo per cui ti sto dando dei link), ma un buon esempio potrebbe essere un'applicazione guidata per la diagnosi medica , che utilizza una combinazione di sintomi per identificare possibili malattie.

Pensa per un momento alla serie di punti dati che comprendono il tuo profilo dati (B + C + E + G + F + K nell'esempio sopra) come Sintomi e Utenti sconosciuti come Malattie . Identificando la malattia, è possibile identificare ulteriormente un trattamento appropriato (trattare questo utente come Utente1).

Ovviamente, una malattia per la quale abbiamo identificato più di 1 Sintomo è più facile da identificare. In effetti, più sintomi siamo in grado di identificare, più facile e accurata sarà la nostra diagnosi.

Ci sono altre alternative?

Ovviamente. In alternativa, potresti creare il tuo semplice algoritmo di punteggio e basarlo su corrispondenze esatte. Questo non è efficiente quanto la probabilità, ma potrebbe essere più semplice da implementare.

Ad esempio, considera questo semplice diagramma dei punteggi:

+ ------------------------- + -------- + ------------ +
| Proprietà | Peso | Importanza |
+ ------------------------- + -------- + ------------ +
| Indirizzo IP reale | 60 | 5 |
| Indirizzo IP proxy utilizzato 40 | 4 |
| Cookie HTTP | 80 | 8 |
| Cookie di sessione | 80 | 6 |
| Cookie di terze parti | 60 | 4 |
| Cookie Flash | 90 | 7 |
| Bug PDF | 20 | 1 |
| Bug Flash | 20 | 1 |
| Bug Java | 20 | 1 |
| Pagine frequenti | 40 | 1 |
| Impronta digitale dei browser | 35 | 2 |
| Plugin installati | 25 | 1 |
| Immagini memorizzate nella cache 40 | 3 |
| URL | 60 | 4 |
| Rilevamento caratteri di sistema | 70 | 4 |
| Deposito locale | 90 | 8 |
| Geolocalizzazione | 70 | 6 |
| AOLTR | 70 | 4 |
| API informazioni di rete | 40 | 3 |
| API di stato della batteria | 20 | 1 |
+ ------------------------- + -------- + ------------ +

Per ogni informazione che puoi raccogliere su una determinata richiesta, assegna il punteggio associato, quindi usa Importanza per risolvere i conflitti quando i punteggi sono uguali.

Verifica teorica

Per una semplice dimostrazione del concetto, dai un'occhiata a Perceptron . Perceptron è un modello di RNA che viene generalmente utilizzato in applicazioni di riconoscimento di schemi. Esiste persino una vecchia classe PHP che la implementa perfettamente, ma probabilmente dovrai modificarla per i tuoi scopi.

Nonostante sia un ottimo strumento, Perceptron può comunque restituire più risultati (possibili corrispondenze), quindi utilizzare un confronto di Punteggio e Differenza è ancora utile per identificare il migliore di tali corrispondenze.

ipotesi

  • Memorizza tutte le informazioni possibili su ciascun utente (IP, cookie, ecc.)
  • Se il risultato è una corrispondenza esatta, aumentare il punteggio di 1
  • Se il risultato non corrisponde esattamente, ridurre il punteggio di 1

aspettativa

  1. Genera etichette RNA
  2. Genera utenti casuali che emulano un database
  3. Genera un singolo utente sconosciuto
  4. Genera RNA e valori dell'utente sconosciuto
  5. Il sistema unirà le informazioni RNA e insegnerà il Perceptron
  6. Dopo l'allenamento di Perceptron, il sistema avrà una serie di ponderazioni
  7. Ora puoi testare il modello dell'utente sconosciuto e Perceptron produrrà un set di risultati.
  8. Memorizza tutte le partite positive
  9. Ordina le partite prima per punteggio, quindi per differenza (come descritto sopra)
  10. Emette le due corrispondenze più vicine o, se non viene trovata alcuna corrispondenza, restituisce risultati vuoti

Codice per Proof of Concept

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

Produzione:

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

Stampa_r di "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
)

Se Debug = true si sarebbe in grado di vedere Input (Sensore e desiderato), Pesi iniziali, Output (Sensore, Somma, Rete), Errore, Correzione e Pesi finali .

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

Da x1 a x20 rappresentano le funzioni convertite dal codice.

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

Ecco una demo online

Classe utilizzata:

class Profile {
    public $name, $data = array(), $score, $diff, $base;

    function __construct($name, array $importance) {
        $values = array(-1, 1); // Perception values
        $this->name = $name;
        foreach ($importance as $item => $point) {
            // Generate Random true/false for real Items
            $this->data[$item] = $values[mt_rand(0, 1)];
        }
        $this->base = array_sum($importance);
    }

    public function setScore($score, $diff) {
        $this->score = $score / $this->base;
        $this->diff = $diff / $this->base;
    }
}

Classe di Perceptron modificata

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

Conclusione

Identificare un utente senza un identificatore univoco non è un'attività semplice o diretta. dipende dalla raccolta di una quantità sufficiente di dati casuali che è possibile raccogliere dall'utente con una varietà di metodi.

Anche se scegli di non utilizzare una rete neurale artificiale, ti suggerisco almeno di usare una matrice di probabilità semplice con priorità e probabilità - e spero che il codice e gli esempi forniti sopra ti diano abbastanza per andare avanti.


@Baba Cosa intendi con "Utilizzo di BLOB" per impronte digitali su un browser?
billmalarky,

@billmalarky Oggetto
Baba

1
@Baba Come si usa per impronte digitali un browser? Basta controllare ciò che è attualmente in esso in un dato momento?
billmalarky,

@Baba ottimo lavoro, ho sempre cercato di avere una strategia multi-livello per identificare un utente, ma come hai detto, la cache può essere cancellata, gli IP cambiati, gli utenti dietro proxy o NAT - specialmente quelle persone - i cookie cancellati, ecc. ma anche con tutto questo sforzo è una probabilità irrilevante, anche se il cattivo utente sta usando Tor browser per esempio, la maggior parte se non tutte le strategie di rilevamento menzionate non funzioneranno. Mi è piaciuto browserleaks.com ma con Tor tutto è tornato indefinito o sconosciuto
Mi-Creativity il

Solo una nota intesa solo a "rimuovere un po 'di polvere" da questo gioiello di una pubblicazione: Elenco di collegamenti interrotti a partire dal 07.09.17: - Implement Bayesian inference using PHP, tutte e 3 le parti. - Frequency vs Probability - Joint Probability -Input (Sensor & Desired), Initial Weights, Output (Sensor, Sum, Network), Error, Correction and Final Weights
Ziezi,

28

Questa tecnica (per rilevare gli stessi utenti senza cookie - o anche senza indirizzo IP) si chiama fingerprinting del browser . Fondamentalmente, esegui la scansione del maggior numero possibile di informazioni sul browser: è possibile ottenere risultati migliori con javascript, flash o java (ad esempio estensioni, font, ecc. Installati. Dopodiché, puoi archiviare i risultati con l'hash, se lo desideri.

Non è infallibile, ma:

L'83,6% dei browser visti presentava un'impronta digitale unica; tra quelli con Flash o Java abilitati, 94,2%. Questo non include i cookie!

Ulteriori informazioni:


penso, è ancora la risposta. se devi identificare un dispositivo, devi solo ottenere quei dati - f.ex.
Sistema

Questo non funzionerà bene. Ogni browser supporta sessioni e cookie. Usa lo strumento giusto per il lavoro.
Man Vs Code

1
@ slash197 per quanto riguarda la cache dei file? intendo usare 1px x 1px supporti flash trasparenti insieme a un file xml contenente un ID generato univoco all'interno (l'xml dovrebbe essere creato una volta sul server prima di essere scaricato nell'HD locale dell'utente) in questo modo anche se l'utente elimina i cookie o si disconnette, puoi comunque avere un bridge usando il metodo sendAndLoad dello script di azione.
Mbarry,

Il minimo di modifica influirà sul risultato hash. ad esempio la versione di Shock Wave Player. possibile soluzione con file cache xml memorizzato localmente con chiave univoca generata + supporti flash nascosti 1px x 1px (script di azione) sul browser, in questo modo si eliminano i cookie, problema di scadenza della sessione se quello era il problema principale. puoi ancora avere il ponte tra il tuo database sql e la chiave sul computer locale dell'utente.
Mbarry,

@Mbarry Non sono un grande fan del flash ma se nel browser è presente un componente aggiuntivo per il blocco del flash come se avessi quel supporto flash da 1x1 pixel sarebbe disabilitato, vero?
slash197

7

Le funzioni di identificazione personale sopra menzionate funzionano, ma possono ancora subire delle colisioni.

Un modo è aggiungere UID all'URL di ogni interazione con l'utente.

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

Dove ogni collegamento nel sito è adattato con questo modificatore. È simile al modo in cui ASP.Net utilizzava i dati FORM tra le pagine.


Ci ho pensato, ma è il modo più semplice per un utente di modificarlo
slash197

1
non dell'id è un hash autoreferenziale. Lo rende crittograficamente sicuro.
Justin Alexander,

Inoltre, questo metodo è ok quando qualcuno sta navigando nel sito ma come proponi di gestire il caso quando un utente che ritorna torna dopo una settimana e digita semplicemente l'indirizzo del sito Web, senza ID?
slash197,

@ slash197 in quel caso perché non dici all'utente di accedere, che cosa succede anche quando l'utente elimina i cookie.
Akash Kava,

6

Hai mai guardato Evercookie ? Potrebbe funzionare o meno sui browser. Un estratto dal loro sito.

"Se un utente viene cucinato su un browser e passa a un altro browser, purché abbia ancora il cookie Local Shared Object, il cookie verrà riprodotto in entrambi i browser."


Mi chiedo se funziona con JavaScript disabilitato. Hai qualche esperienza?
Voitcus,

Si chiama evercookie per un motivo, funzionerà qualunque cosa accada. È quasi impossibile per loro rimuovere il cookie.
Alexis Tyler,

Non funzionerà, qualunque cosa accada. Dalla prima riga della descrizione: "evercookie è un'API javascript ...". Non funzionerà se javascript è disabilitato.
gdw2,

Non deve essere nemmeno disabilitato. Ghostery e uBlock lanciano evercookie
opengrid

3

Potresti farlo con un png memorizzato nella cache, sarebbe in qualche modo inaffidabile (diversi browser si comportano in modo diverso e fallirà se l'utente cancella la cache), ma è un'opzione.

1: imposta un database che memorizza un ID utente univoco come stringa esadecimale

2: crea un file genUser.php (o qualunque altra lingua) che generi un ID utente, lo memorizza nel DB e quindi crea un vero colore .png dai valori di quella stringa esadecimale (ogni pixel sarà di 4 byte) e restituisce quello al browser. Assicurati di impostare il tipo di contenuto e le intestazioni della cache.

3: in HTML o JS creare un'immagine simile <img id='user_id' src='genUser.php' />

4: disegna quell'immagine su una tela ctx.drawImage(document.getElementById('user_id'), 0, 0);

5: leggi i byte di quell'immagine usando ctx.getImageDatae converti gli interi in una stringa esadecimale.

6: Questo è il tuo ID utente univoco che ora è memorizzato nella cache sul computer degli utenti.


Vuole qualcosa che possa tracciare l'utente "attraverso i browser" che non funzionerà qui (ogni browser ha il proprio database di cache).
EricLaw,

Dove lo vedi, la sua domanda chiede solo "Hai dimenticato di dire che dovrebbe essere compatibile con più browser", vale a dire lavorare in qualsiasi browser.
hobberwickey,

La sua domanda è scritta male. I'm after device recognitionè l'omaggio per quello che vuole, e lui elabora qui: stackoverflow.com/questions/15966812/...
EricLaw

2

Sulla base di ciò che hai detto:

Fondamentalmente sto cercando il riconoscimento del dispositivo non proprio l'utente

Il modo migliore per farlo è inviare l'indirizzo mac che è l'ID NIC.

Puoi dare un'occhiata a questo post: Come posso ottenere il MAC e l'indirizzo IP di un client connesso in PHP?


Siamo spiacenti, ma l'ID NIC è facilmente falsificabile. Non è sicuramente il modo migliore.
as

Il fingerprinting del browser @asgs sarebbe forse migliore, o quale sarebbe il modo migliore secondo te?
Mehdi Karamosly,

Non esiste un modo migliore, questa è la parte triste. Tuttavia, questo e Browser FingerPrinting in combinazione con lo studio di Probabilità che Baba ha presentato sopra sarebbe il migliore secondo me.
chiede il

1

Puoi farlo con etags. Anche se non sono sicuro che questo legale come un mucchio di cause legali siano state presentate.

Se avverti correttamente i tuoi utenti o se hai qualcosa come un sito Web Intranet, potrebbe andare bene.


Gli Etag non sono compatibili con più browser.
slash197,

1
Gli etag fanno parte delle specifiche HTTP / 1.1. Tutti i browser più diffusi supportano etags, avresti praticamente bisogno di scrivere il tuo browser per non supportare le intestazioni ETag / If-None-Match.
Brian McGinity,

Non ho detto che non lo supporta, ho detto che non è compatibile con più browser. Se un tag viene salvato in Firefox non è disponibile in Chrome, quindi il contenuto verrà scaricato di nuovo poiché non c'è cache.
slash197,

Ora capisco cosa stavi dicendo. Hai ragione. Ogni browser ha il proprio archivio cache, quindi etags differenti.
Brian McGinity,


0

Inefficiente, ma può darti i risultati desiderati, sarebbe il polling di un'API dalla tua parte. Avere un processo in background sul lato client che invia i dati dell'utente a intervalli. Avrai bisogno di un identificatore utente da inviare alla tua API. Una volta che hai che è possibile inviare insieme tutte le informazioni associate a quell'identificatore univoco.

Ciò elimina la necessità di cookie e archiviazione locale.


0

Non ci posso credere, http://browserspy.dk non è ancora stato menzionato qui! Il sito descrive molte funzionalità (in termini di riconoscimento dei modelli), che potrebbero essere utilizzate per creare un classificatore.

E di causa, per valutare le funzionalità suggerirei Support Vector Machines e libsvm in particolare.


0

Tracciarli durante una sessione o tra le sessioni?

Se il tuo sito è HTTPS ovunque, puoi utilizzare l'ID sessione TLS per tenere traccia della sessione dell'utente


1
la domanda qui è come?
user455318

-2
  1. creare un plug-in fittizio multipiattaforma (nsapi) e generare un nome univoco per il nome o la versione del plug-in quando l'utente lo scarica (ad es. dopo il login).
  2. fornire un programma di installazione per il plug-in / installarlo secondo la politica

questo richiederà all'utente di installare volontariamente l'identificatore.

una volta installato il plug-in, l' impronta digitale di qualsiasi browser (plug-in abilitato) conterrà questo plug-in specifico. Per restituire le informazioni a un server, è necessario un algoritmo per rilevare efficacemente il plugin sul lato client, altrimenti IE e Firefox> = 28 utenti avranno bisogno di una tabella di possibili identificazioni valide.

Ciò richiede un investimento relativamente elevato in una tecnologia che probabilmente verrà chiusa dai fornitori di browser. Quando sei in grado di convincere i tuoi utenti a installare un plugin, potrebbero esserci anche opzioni come installare un proxy locale , usare vpn o patchare i driver di rete.

Gli utenti che non vogliono essere identificati (o le loro macchine) troveranno sempre un modo per impedirlo.


Ciao benvenuto per impilare overflow. Notare che; this will require the user to willingly install the identifier.probabilmente non è quello che intendeva il poster originale (OP).
Stefan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.