私は分析ツールを作成しており、現在、ユーザーエージェントからユーザーのIPアドレス、ブラウザ、オペレーティングシステムを取得できます。
Cookieやローカルストレージを使用せずに同じユーザーを検出する可能性があるのでしょうか。ここにコード例を期待していません。どこを見ればよいかを示す簡単なヒントです。
同じコンピューター/デバイスの場合は、クロスブラウザー互換である必要があることを言及するのを忘れていました。基本的に、私は実際にはユーザーではなくデバイスを認識した後です。
私は分析ツールを作成しており、現在、ユーザーエージェントからユーザーのIPアドレス、ブラウザ、オペレーティングシステムを取得できます。
Cookieやローカルストレージを使用せずに同じユーザーを検出する可能性があるのでしょうか。ここにコード例を期待していません。どこを見ればよいかを示す簡単なヒントです。
同じコンピューター/デバイスの場合は、クロスブラウザー互換である必要があることを言及するのを忘れていました。基本的に、私は実際にはユーザーではなくデバイスを認識した後です。
回答:
前書き
私があなたを正しく理解している場合は、一意の識別子を持っていないユーザーを特定する必要があるため、ランダムデータと照合することで、ユーザーが誰であるかを把握したいとします。次の理由により、ユーザーのIDを確実に保存できません。
JavaアプレットまたはComオブジェクトは、ハードウェア情報のハッシュを使用する簡単な解決策でしたが、最近の人々は非常にセキュリティを意識しているため、システムにこれらの種類のプログラムをインストールすることは困難です。これにより、Cookieやその他の同様のツールを使用できなくなります。
Cookieおよびその他の同様のツール
データプロファイルを作成してから、確率テストを使用して見込みユーザーを特定することを検討してください。これに役立つプロファイルは、次のいくつかの組み合わせによって生成できます。
私がリストした項目は、もちろん、ユーザーを一意に識別することができるいくつかの可能な方法です。他にもたくさんあります。
データプロファイルを作成するためのこのランダムデータ要素のセットを使用して、次は何をしますか?
次のステップは、いくつかのファジーロジック、または、いっそのこと、人工ニューラルネットワーク(ファジーロジックを使用する)を開発することです。どちらの場合も、アイデアはシステムをトレーニングし、そのトレーニングをベイジアン推論と組み合わせて結果の精度を高めることです。
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クラスもありますが、目的に応じて変更する必要がある可能性があります。
優れたツールであるにもかかわらず、パーセプトロンは複数の結果(一致する可能性があります)を返すことができるため、スコアと差分の比較を使用すると、それらの一致の最良のものを識別するのに役立ちます。
仮定
期待
概念実証のコード
$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
結論
一意の識別子なしでユーザーを識別することは、単純明快な作業ではありません。それは、さまざまな方法でユーザーから収集できる十分な量のランダムデータを収集することに依存しています。
人工ニューラルネットワークを使用しないことを選択した場合でも、少なくとも優先度と可能性を備えた単純な確率行列を使用することをお勧めします。上記のコードと例で十分に進むことができれば幸いです。
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
この手法(Cookieを使用せずに、またはIPアドレスを使用せずに同じユーザーを検出する)は、ブラウザフィンガープリントと呼ばれます。基本的には、できる限りブラウザに関する情報としてクロールします。より良い結果を得るには、javascript、flash、またはjava(f.ex.インストールされている拡張機能、フォントなど)を使用します。その後、必要に応じて、結果をハッシュ化して保存できます。
それは完全ではありませんが:
表示されたブラウザの83.6%に固有の指紋がありました。FlashまたはJavaを有効にしたものの94.2%。これにはクッキーは含まれません!
より詳しい情報:
上記の拇印は機能しますが、コリジョンが発生する可能性があります。
1つの方法は、ユーザーとの各対話のURLにUIDを追加することです。
http://someplace.com/12899823/user/profile
ここでは、サイト内のすべてのリンクがこの修飾子で調整されています。これは、ASP.Netがページ間でFORMデータを使用して作業する方法に似ています。
Evercookieを調べましたか?ブラウザ間で機能する場合と機能しない場合があります。彼らのサイトからの抜粋。
「ユーザーが1つのブラウザーでCookieを取得し、別のブラウザーに切り替えた場合、ローカル共有オブジェクトCookieがまだある限り、Cookieは両方のブラウザーで再現されます。」
キャッシュされた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です。
I'm after device recognition
彼が望んでいる何のためにプレゼントがある、と彼はここでは詳しく説明:stackoverflow.com/questions/15966812/...
あなたが言ったことに基づいて:
基本的に、私は実際にはユーザーではなくデバイスを認識した後です
最善の方法は、NIC IDであるMACアドレスを送信することです。
あなたはこの投稿を見ることができます: 接続されたクライアントのMACとIPアドレスをPHPでどのように取得できますか?
あなたはetagsでそれを行うことができます。一連の訴訟としてこの法的訴訟が提起されたかどうかはわかりませんが。
ユーザーに適切に警告する場合、またはイントラネットWebサイトのようなものがある場合は、問題ない可能性があります。
デバイス識別子を格納するためのBLOBを作成する可能性があります...
欠点は、ブラウザーがファイルシステムにアクセスしてファイルを直接保存できないため、ユーザーがblobをダウンロードする必要があることです(ダウンロードを強制できます)。
参照:
https://www.inkling.com/read/javascript-definitive-guide-david-flanagan-6th/chapter-22/blobs
信じられない、http://browserspy.dkまだここで言及されていません!このサイトでは、(パターン認識の観点から)分類子を構築するために使用できる多くの機能について説明しています。
セッション中またはセッション間で追跡しますか?
サイトがHTTPS Everywhereの場合、TLSセッションIDを使用してユーザーのセッションを追跡できます
これは、ユーザーが識別子を進んでインストールすることを要求します。
プラグインがインストールされると、任意の(プラグインが有効な)ブラウザーのフィンガープリントにこの特定のプラグインが含まれます。情報をサーバーに返すには、クライアント側のプラグインを効果的に検出するアルゴリズムが必要です。そうでない場合、IEとFirefox> = 28のユーザーは、有効なIDの表が必要になります。
これには、ブラウザーベンダーによってシャットダウンされる可能性が高いテクノロジへの比較的高い投資が必要です。ユーザーにプラグインをインストールするように説得できる場合は、ローカルプロキシのインストールなどのオプションもあります。 VPNの使用、ネットワークドライバーのパッチ。
識別されたくないユーザー(またはそのマシン)は、常にそれを防ぐ方法を見つけます。
this will require the user to willingly install the identifier.
おそらく、元のポスター(OP)が意図したものではありません。