Cookieまたはローカルストレージなしのユーザー認識


132

私は分析ツールを作成しており、現在、ユーザーエージェントからユーザーのIPアドレス、ブラウザ、オペレーティングシステムを取得できます。

Cookieやローカルストレージを使用せずに同じユーザーを検出する可能性があるのでしょうか。ここにコード例を期待していません。どこを見ればよいかを示す簡単なヒントです。

同じコンピューター/デバイスの場合は、クロスブラウザー互換である必要があることを言及するのを忘れていました。基本的に、私は実際にはユーザーではなくデバイスを認識した後です。


5
実際にはそうではありません。少なくとも、正確であるために信頼できる方法はありません。たぶん3つすべてを組み合わせたハッシュかもしれませんが、家の中で複数の人が同じブラウザとOSを使用している場合は、それでも機能しません。また、ほとんどのISPは動的IPアドレスを提供します。つまり、それらは頻繁に変更されるため、識別の目的で使用することもできません。
Jon

2
次に、セッションが何であるかがわかりません。あなたのユースケースはまさにセッションがそのために設計されたものです。セッションは、ログインや認証とは何の関係もありません。Webサーバーは、セッション識別子を含むCookieを送信するようクライアントに指示します。クライアントは、クライアントから送信されたセッションIDを使用して識別します。
Man Vs Code

4
クッキーはまだ機能しますか?なぜクッキーを使わないのですか?
ババ

2
それは本当に簡単で、私はいつもそれを使っています、ユーザー名とパスワードを入力するようにユーザーに頼みます!!!
Amit Kriplani 2013

2
これは最小限のJavaScriptソリューションです(この場合はクロスブラウザーではありません):github.com/carlo/jquery-browser-fingerprint多くのプラグインがデフォルトでクロスブラウザーでインストールされているという概念に私を連れて来たので、私はそれについて言及しましたユーザー側の任意の選択。それらを注意深く分類することは(小さな作業ではありませんが、それでも...)、より大きなデバイスベースのフィンガープリントの具体的なブラウザーに依存しないプロパティにつながる可能性があります。
hexalys 2013

回答:


389

前書き

私があなたを正しく理解している場合は、一意の識別子を持っていないユーザーを特定する必要があるため、ランダムデータと照合することで、ユーザーが誰であるかを把握したいとします。次の理由により、ユーザーのIDを確実に保存できません。

  • クッキーは削除できます
  • IPアドレスは変更可能
  • ブラウザは変わる可能性があります
  • ブラウザキャッシュが削除される可能性があります

JavaアプレットまたはComオブジェクトは、ハードウェア情報のハッシュを使用する簡単な解決策でしたが、最近の人々は非常にセキュリティを意識しているため、システムにこれらの種類のプログラムをインストールすることは困難です。これにより、Cookieやその他の同様のツールを使用できなくなります。

Cookieおよびその他の同様のツール

データプロファイルを作成してから、確率テストを使用して見込みユーザーを特定することを検討してください。これに役立つプロファイルは、次のいくつかの組み合わせによって生成できます。

  1. IPアドレス
    • 実際のIPアドレス
    • プロキシIPアドレス(ユーザーは多くの場合、同じプロキシを繰り返し使用します)
  2. クッキー
  3. Webバグ(バグは修正されるため信頼性は低くなりますが、それでも有用です)
    • PDFバグ
    • フラッシュバグ
    • Javaバグ
  4. ブラウザー
    • クリック追跡(多くのユーザーが各訪問で同じ一連のページにアクセスします)
    • ブラウザフィンガープリント-インストールされたプラグイン(多くの場合、人々はさまざまな独自のプラグインセットを持っています)
    • キャッシュされた画像(ユーザーはCookieを削除することがありますが、キャッシュされた画像を残します)
    • Blobの使用
    • URL(ブラウザの履歴またはCookieには、https://stackoverflow.com/users/1226894http://www.facebook.com/barackobama?fref=tsなどのURLに一意のユーザーIDが含まれている場合があります
    • システムフォントの検出(これはあまり知られていませんが、多くの場合一意の調号です)
  5. HTML5とJavaScript
    • HTML5 LocalStorage
    • HTML5 Geolocation APIと逆ジオコーディング
    • アーキテクチャ、OS言語、システム時間、画面解像度など
    • ネットワーク情報API
    • バッテリーステータスAPI

私がリストした項目は、もちろん、ユーザーを一意に識別することができるいくつかの可能な方法です。他にもたくさんあります。

データプロファイルを作成するためのこのランダムデータ要素のセットを使用して、次は何をしますか?

次のステップは、いくつかのファジーロジック、または、いっそのこと、人工ニューラルネットワーク(ファジーロジックを使用する)を開発することです。どちらの場合も、アイデアはシステムをトレーニングし、そのトレーニングをベイジアン推論と組み合わせて結果の精度を高めることです。

人工ニューラルネットワーク

PHP用のNeuralMeshライブラリを使用すると、人工ニューラルネットワークを生成できます。ベイジアン推論を実装するには、次のリンクを確認してください。

この時点で、あなたは考えているかもしれません:

一見単純なタスクになぜそれほど多くの数学と論理が必要なのでしょうか?

基本的に、それは簡単な仕事ではないからです。実際に達成しようとしているのは、純粋な確率です。たとえば、次の既知のユーザーがあるとします。

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である確率はどれくらいですか?そして、これらの2つの一致のどちらが最も可能性が高いですか?

この質問に効果的に回答するには、頻度と確率の形式、およびなぜ結合確率の方が優れたアプローチであるかを理解する必要があります。詳細はここで説明するには多すぎます(これがリンクを提供している理由です)が、考えられる病気を特定するために症状の組み合わせを使用するMedical Diagnosis Wizardアプリケーションが良い例です。

データプロファイル(上記の例ではB + C + E + G + F + K)を症状として、不明なユーザーを疾患として構成する一連のデータポイントについて考えてみます。疾患を特定することで、適切な治療をさらに特定できます(このユーザーをUser1として治療します)。

明らかに、私たちが複数の症状を特定した疾患は、特定するのが簡単です。実際、特定できる症状が多ければ多いほど、診断はより簡単かつ正確になります。

他の選択肢はありますか?

もちろん。別の方法として、独自の単純なスコアリングアルゴリズムを作成し、完全一致に基づいて計算することができます。これは確率ほど効率的ではありませんが、実装する方が簡単な場合があります。

例として、次の単純なスコアチャートを考えます。

+ ------------------------- + -------- + ------------ +
| プロパティ| 重量| 重要性|
+ ------------------------- + -------- + ------------ +
| 実際のIPアドレス| 60 | 5 |
| 使用されたプロキシIPアドレス| 40 | 4 |
| HTTP Cookie | 80 | 8 |
| セッションCookie | 80 | 6 |
| サードパーティのクッキー| 60 | 4 |
| フラッシュクッキー| 90 | 7 |
| PDFバグ| 20 | 1 |
| フラッシュバグ| 20 | 1 |
| Javaバグ| 20 | 1 |
| 頻繁なページ| 40 | 1 |
| ブラウザのフィンガープリント| 35 | 2 |
| インストールされているプラ​​グイン| 25 | 1 |
| キャッシュされた画像| 40 | 3 |
| URL | 60 | 4 |
| システムフォントの検出| 70 | 4 |
| Localstorage | 90 | 8 |
| ジオロケーション| 70 | 6 |
| AOLTR | 70 | 4 |
| ネットワーク情報API | 40 | 3 |
| バッテリーステータスAPI | 20 | 1 |
+ ------------------------- + -------- + ------------ +

特定のリクエストで収集できる各情報について、関連するスコアを付与し、重要度を使用してスコアが同じ場合の競合を解決します。

コンセプトの証明

簡単な概念実証については、パーセプトロンをご覧ください。パーセプトロンは、パターン認識アプリケーションで一般的に使用されるRNAモデルです。完全に実装する古いPHPクラスもありますが、目的に応じて変更する必要がある可能性があります。

優れたツールであるにもかかわらず、パーセプトロンは複数の結果(一致する可能性があります)を返すことができるため、スコアと差分の比較を使用すると、それらの一致の最良のものを識別するのに役立ちます。

仮定

  • 各ユーザーに関するすべての可能な情報(IP、Cookieなど)を保存します
  • 結果が完全一致の場合、スコアを1増やします
  • 結果が完全に一致しない場合は、スコアを1減らします

期待

  1. RNAラベルを生成する
  2. データベースをエミュレートするランダムユーザーを生成する
  3. 単一の不明なユーザーを生成する
  4. 未知のユーザーRNAと値を生成する
  5. システムはRNA情報をマージし、パーセプトロンを教えます
  6. パーセプトロンをトレーニングした後、システムには一連の重みがあります
  7. これで、不明なユーザーのパターンをテストできます。パーセプトロンは結果セットを生成します。
  8. ポジティブマッチをすべて保存
  9. 最初に一致をスコアでソートし、次に差分でソートします(上記のとおり)。
  10. 最も近い2つの一致を出力します。一致が見つからない場合は、空の結果を出力します

概念実証のコード

$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)

「D」のPrint_r:

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

結論

一意の識別子なしでユーザーを識別することは、単純明快な作業ではありません。それは、さまざまな方法でユーザーから収集できる十分な量のランダムデータを収集することに依存しています。

人工ニューラルネットワークを使用しないことを選択した場合でも、少なくとも優先度と可能性を備えた単純な確率行列を使用することをお勧めします。上記のコードと例で十分に進むことができれば幸いです。


@Baba「Blobを使用して」ブラウザのフィンガープリントを作成するとはどういう意味ですか?
billmalarky 2014年


1
@Babaブラウザをフィンガープリントするためにそれをどのように使用しますか?いつでも現在何が入っているかを確認してください。
billmalarky 2014年

@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
ジーッチ

28

この手法(Cookieを使用せずに、またはIPアドレスを使用せずに同じユーザーを検出する)は、ブラウザフィンガープリントと呼ばれます。基本的には、できる限りブラウザに関する情報としてクロールします。より良い結果を得るには、javascript、flash、またはjava(f.ex.インストールされている拡張機能、フォントなど)を使用します。その後、必要に応じて、結果をハッシュ化して保存できます。

それは完全ではありませんが:

表示されたブラウザの83.6%に固有の指紋がありました。FlashまたはJavaを有効にしたものの94.2%。これにはクッキーは含まれません!

より詳しい情報:


私はそれがまだ答えだと思います。デバイスを識別する必要がある場合は、それらのデータを取得するだけで済みます-f.ex。OS、一般的な拡張機能(およびそのバージョン)、インストールされているフォントなど
pozs '18 / 04/13

これはうまくいきません。すべてのブラウザがセッションとCookieをサポートしています。ジョブに適したツールを使用します。
Man Vs Code

1
@ slash197ファイルキャッシュはどうですか?つまり、ユーザーがCookieを削除したりログアウトしたりしても、1px x 1pxの透明なフラッシュメディアと、固有の生成されたIDを内部に保持するxmlファイル(ユーザーのローカルHDにダウンロードする前に、サーバーで一度作成する必要があります)を使用します。アクションスクリプトのsendAndLoadメソッドを使用して、引き続きブリッジを作成できます。
Mbarry 2013

最小限の変更がハッシュ結果に影響します。たとえば、衝撃波プレーヤーのバージョン。一意のキーが生成されたローカルに保存されたxmlキャッシュファイルとブラウザーで非表示の1px x 1pxフラッシュメディア(アクションスクリプト)を使用して可能な解決策。SQLデータベースとユーザーローカルマシンのキーの間のブリッジを維持できます。
Mbarry

@Mbarry私はそれほどフラッシュファンではありませんが、ブラウザで1x1ピクセルのフラッシュメディアが無効になっているようなフラッシュブロックアドオンがある場合、問題はありませんか?
slash197 2013

7

上記の拇印は機能しますが、コリジョンが発生する可能性があります。

1つの方法は、ユーザーとの各対話のURLにUIDを追加することです。

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

ここでは、サイト内のすべてのリンクがこの修飾子で調整されています。これは、ASP.Netがページ間でFORMデータを使用して作業する方法に似ています。


私はそれを考えましたが、それはユーザーが変更する最も簡単な方法です
slash197

1
idは自己参照ハッシュではありません。暗号的に安全にします。
Justin Alexander

また、この方法は誰かがサイトを閲覧している場合でも問題ありませんが、リピーターが1週間後に戻ってきて、ウェブサイトのアドレスをIDなしで単に入力した場合の対処方法を教えてください。
slash197 2013

@ slash197その場合、なぜユーザーにログインするように指示しないのか、ユーザーがCookieを削除した場合でもどうなるか。
Akash Kava

6

Evercookieを調べましたか?ブラウザ間で機能する場合と機能しない場合があります。彼らのサイトからの抜粋。

「ユーザーが1つのブラウザーでCookieを取得し、別のブラウザーに切り替えた場合、ローカル共有オブジェクトCookieがまだある限り、Cookieは両方のブラウザーで再現されます。」


JavaScriptを無効にしても動作するのでしょうか。何か経験はありますか?
Voitcus 2013年

それは理由のためにエバークッキーと呼ばれ、それは何があっても機能します。彼らがクッキーを削除することはほとんど不可能です。
Alexis Tyler

何があっても機能しません。説明の最初の行から: 'evercookie is a JavaScript API ...' JavaScriptが無効になっている場合は機能しません。
gdw2

jsを無効にする必要さえありません。ゴーストリーとuBlockがevercookieをドロップ
opengrid

3

キャッシュされたpngを使用してこれを行うことができますが、多少信頼性が低くなります(ブラウザーによって動作が異なり、ユーザーがキャッシュをクリアすると失敗します)が、これはオプションです。

1:一意のユーザーIDを16進数の文字列として格納するデータベースを設定する

2:ユーザーIDを生成するgenUser.php(または任意の言語)ファイルを作成し、DBに保存してから、その16進数文字列の値からTrue Color .pngを作成し(各ピクセルは4バイトになります)、それをブラウザに。必ずコンテンツタイプとキャッシュヘッダーを設定してください。

3:HTMLまたはJSで次のような画像を作成します <img id='user_id' src='genUser.php' />

4:その画像をキャンバスに描画します ctx.drawImage(document.getElementById('user_id'), 0, 0);

5:を使用してその画像のバイトを読み取り、ctx.getImageData整数を16進文字列に変換します。

6:これは、ユーザーのコンピューターにキャッシュされている固有のユーザーIDです。


彼は、「ブラウザー間で」ユーザーを追跡できるものを望んでいます。これはここでは機能しません(各ブラウザーには独自のキャッシュデータベースがあります)。
EricLaw

あなたはそれをどこで見ていますか、彼の質問は「クロスブラウザ互換である必要があることを言及するのを忘れた」、つまりどのブラウザでも機能することだけを求めています。
-hobberwickey

彼の質問は不十分に書かれている。I'm after device recognition彼が望んでいる何のためにプレゼントがある、と彼はここでは詳しく説明:stackoverflow.com/questions/15966812/...
EricLaw

2

あなたが言ったことに基づいて:

基本的に、私は実際にはユーザーではなくデバイスを認識した後です

最善の方法は、NIC IDであるMACアドレスを送信することです。

あなたはこの投稿を見ることができます: 接続されたクライアントのMACとIPアドレスをPHPでどのように取得できますか?


NIC IDは簡単に偽装できます。それは間違いなく最良の方法ではありません。
15

@asgsブラウザのフィンガープリントは多分より良いでしょう、またはあなたの意見では何が最善の方法でしょうか?
Mehdi Karamosly、2015

最善の方法はありません。それが悲しい部分です。しかし、それと、Babaが上に示した確率調査と組み合わせたBrowser FingerPrintingは、私の意見では最高でしょう。
2015

1

あなたはetagsでそれを行うことができます。一連の訴訟としてこの法的訴訟が提起されたかどうかはわかりませんが。

ユーザーに適切に警告する場合、またはイントラネットWebサイトのようなものがある場合は、問題ない可能性があります。


Etagは、ブラウザ間で互換性がありません。
slash197 2013

1
EtagsはHTTP / 1.1仕様の一部です。すべての一般的なブラウザーはetagをサポートしています。ETag/ If-None-Matchヘッダーをサポートしないようにするには、独自のブラウザーを作成する必要があります。
Brian McGinity 2013

私はそれがそれをサポートしないとは言いませんでした、それはクロスブラウザ互換性がないと言いました。タグがFirefoxに保存されている場合、Chromeでは使用できません。キャッシュがないため、コンテンツは再度ダウンロードされます。
slash197

今、私はあなたが言っていたことを理解しています。あなたが正しい。各ブラウザーには独自のキャッシュストアがあるため、etagが異なります。
ブライアンマクジニティ2013


0

非効率的ですが、望ましい結果が得られる可能性がある場合は、APIをポーリングすることになります。一定の間隔でユーザーデータを送信するクライアント側のバックグラウンドプロセスを用意します。APIに送信するには、ユーザーIDが必要です。これを取得したら、その一意の識別子に関連付けられた情報を送信できます。

これにより、Cookieとlocalstorageが不要になります。



0

セッション中またはセッション間で追跡しますか?

サイトがHTTPS Everywhereの場合、TLSセッションIDを使用してユーザーのセッションを追跡できます


1
ここでの質問はどうですか?
user455318

-2
  1. クロスプラットフォームのダミー(nsapi)プラグインを作成し、ユーザーがプラグインをダウンロードするとき(ログイン後など)にプラグイン名またはバージョンの一意の名前を生成します。
  2. プラグインのインストーラーを提供する/ポリシーごとにインストールする

これは、ユーザーが識別子を進んでインストールすることを要求します。

プラグインがインストールされると、任意の(プラグインが有効な)ブラウザーのフィンガープリントにこの特定のプラグインが含まれます。情報をサーバーに返すには、クライアント側のプラグインを効果的に検出するアルゴリズムが必要です。そうでない場合、IEとFirefox> = 28のユーザーは、有効なIDの表が必要になります。

これには、ブラウザーベンダーによってシャットダウンされる可能性が高いテクノロジへの比較的高い投資が必要です。ユーザーにプラグインをインストールするように説得できる場合は、ローカルプロキシのインストールなどのオプションもあります。 VPNの使用、ネットワークドライバーのパッチ。

識別されたくないユーザー(またはそのマシン)は、常にそれを防ぐ方法を見つけます。


こんにちは、スタックオーバーフローへようこそ。ご注意ください; this will require the user to willingly install the identifier.おそらく、元のポスター(OP)が意図したものではありません。
Stefan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.