- フィンガープリントの矛盾が検知シグナルになる仕組みと典型パターン
- 整合性チェックの設計観点(HTTP/JS/描画/環境の横断)
- スクレイピング側が詰みやすい落とし穴と対処方針
フィンガープリントの矛盾が検知に使われやすい理由
結論から言うと、ブラウザフィンガープリントの矛盾は、対策側にとって誤検知が少ないシグナルになりやすいからです。単一の値(例:User-Agent)だけでは偽装が簡単です。一方で、HTTPヘッダ・JavaScript API・レンダリング結果・OS由来情報が相互に矛盾なく揃っている状態を作るのは難しく、コストも上がります。
さらに、矛盾は「どこをいじったか」を示唆します。たとえば UA だけを変更すると、UA と UA-CH(Client Hints)や JS 側の情報がズレやすく、検知側は「人間の通常ブラウジングでは起きにくいズレ」を高精度に拾えます。
押さえたいポイント
検知は「あなたが何者か」を当てにいくだけではありません。
「通常のブラウザ実装として成立しているか(整合的か)」を見て、成立していなければ弾く、という発想が実務的に強いです。
整合性チェックの全体像
整合性チェックは、ざっくり次のレイヤーを横断して行われます。
| レイヤー | 代表的な観測点 | 矛盾の例 |
|---|---|---|
| HTTP | User-Agent / UA-CH / Accept-Language | UAがiPhoneなのに Sec-CH-UA-Platform が “Windows” |
| JavaScript | navigator / Intl / screen / WebRTC | timezoneは米国なのに言語やOS系が不自然 |
| 描画/性能 | Canvas / WebGL / Audio / FPS | GPUが仮想環境特有なのに画面解像度が端末と合わない |
| 挙動 | 入力イベント/スクロール/フォーカス | 人間らしいイベントが不足、または過剰に規則的 |
ここからが本題です。特に近年は、UA 文字列よりも UA-CH(User-Agent Client Hints) の比重が上がり、「UA と UA-CH と JS(navigator.userAgentData)が一致しているか」が見られやすくなっています。
UAとUA-CHの矛盾
Sec-CH-UA
UA-CH(User-Agent Client Hints)の代表例が Sec-CH-UA です。
MDN では、このヘッダは「ブラウザのブランド(例: Chrome)やメジャーバージョンなど、ユーザーエージェントに関する情報」を提供する
低エントロピーヒントとして説明されています。
また、許可ポリシー等でブロックされない限り、既定で送られ得る点も重要です。
※実際にChromeブラウザで送られるリクエストヘッダ

User-Agent ヘッダだけを差し替えると、UA-CH 側(Sec-CH-UA / Sec-CH-UA-Platform / Sec-CH-UA-Mobile など)との整合が崩れやすく、検知に直結します。
特に「Safariっぽい UA 文字列」なのに
Sec-CH-UA が "Chromium" を名乗っている、のような組み合わせは分かりやすい異常です。navigator.userAgentData
Chrome系では、UA-CH は HTTP ヘッダだけでなく、JavaScript 側の navigator.userAgentData でも参照できます。
検知側は、HTTPで見える値とJSで見える値が「同一クライアントとして自然か」を突き合わせます。つまり、どこか一箇所を偽装しても、別経路の観測値が“正直”なら矛盾になります。
よくある矛盾パターン
実務で特に遭遇頻度が高い矛盾を、チェック観点として列挙します(「これを揃えれば必ず通る」という意味ではなく、「崩れると落ちやすい」観点です)。
OSと入力デバイス
- モバイルUAなのに
Sec-CH-UA-Mobileが?0(または逆) - iOS想定なのにタッチイベントやポインタ特性がデスクトップ相当
言語と地域設定
Accept-Languageとnavigator.languagesが乖離Intl.DateTimeFormat().resolvedOptions().timeZoneと IP由来の地域が極端に不自然
画面とウィンドウ
screen.width/heightとwindow.innerWidth/innerHeightの関係が不自然(装飾/ズーム/デバイスピクセル比の整合が崩れる)- タブ内の viewport だけを固定値にして、OSスケーリングや DPR と矛盾
WebGLとGPU
- WebGLのベンダ/レンダラが仮想環境(ソフトウェアレンダラ)特有なのに、UAや性能がハイエンド端末相当
- 描画結果(Canvas/WebGL)とフォント環境が矛盾
現場の勘所
「値の正しさ」より「値同士の関係が自然か」が重要です。たとえば解像度そのものが多少変でも、DPR・ズーム・UA-CH・OSが一貫していれば通るケースはあります。一方で、どれかが突出して矛盾すると一気に怪しく見えます。
検知側が使う整合性の判定方法
検知側が整合性を見る方法は大きく2つです。
ルールベース
「この組み合わせはあり得ない」という明確なNGを弾く方式です。例としては「UAは Android だが Sec-CH-UA-Platform が macOS」など、仕様や実装から外れるものが該当します。コストが低く、誤検知も比較的少ないため最初に導入されがちです。
スコアリング
単発では弱い矛盾も、複数積み上がるとリスクが上がる、として点数化します。たとえば、言語・タイムゾーン・フォント・WebGL の軽微なズレを合算し、閾値を超えたら CAPTCHA や追加認証に回す、といった運用です。
W3C のフィンガープリンティング対策ガイダンスでは、以下のように述べられています。
「フィンガープリントは、複数の観測可能な特徴を組み合わせることで成立し得る。
そのため、仕様を設計する際には、どの情報が識別に寄与し得るか(フィンガープリント面)と、その影響を評価することが重要である。」(※原文の一部をもとにした要約)
※ W3C: WWW(ウェブ)で使用される技術(HTML, CSS, DOM, HTTPなど)の標準化を推進する国際的な非営利団体のこと
スクレイピングする側がやりがちなミス
UAだけ差し替え
最も多い失敗です。UA 文字列は変えられても、UA-CH ヘッダや navigator.userAgentData が変わらない/変えられない構成だと、整合性チェックに引っかかりやすくなります。
ヘッダの過不足
UA-CH はサーバが Accept-CH で要求した場合に追加で送られるものもあります(高エントロピー)。これを無理に固定値で常送すると、かえって「そのサイトで通常は付かない/その順序にならない」などの違和感が出ることがあります。
WAFとの相性
Chromium の UA-CH 解説では、sec-ch-ua のようなヘッダ値に含まれる文字(ダブルクォート等)が、WAF などで「怪しい」と誤判定される互換性問題に触れています。つまり、ボット検知以前に基盤側で落ちるケースもあり得ます。
スクレイピング時に整合性を作る手順
「検知を回避する具体手順」を断定する形ではなく、整合性設計の基本手順として整理します。守りの観点でも、テスト観点としても有効です。
観測点を棚卸し
- HTTP: UA / UA-CH / Accept-Language など
- JS: navigator / Intl / screen / permissions など
- 描画: Canvas / WebGL / フォント
- 挙動: 入力イベント、ページ遷移、待機
基準プロファイルを決める
たとえば「Chrome(Windows 11、x64、デスクトップ)」のように、まず1つの“正のプロファイル”を決めます。重要なのは「それっぽい値」ではなく「その環境なら自然に観測される値の集合」です。
差分を最小化
すべてをカスタムしようとすると矛盾が増えます。実は、変更点を減らすほど整合性は保ちやすいです。特に UA/UA-CH/JS の3経路は、同じ事実(OSやモバイル判定)を別ルートで観測されるため、ここだけは最優先で整合を取ります。
実際のリクエストで送られる情報の確認
整合性が取れているかの確認のために、以下のようなコードで実際のリクエストで送られる情報の確認をしておきましょう。
# 例: Playwright 等での検証時に「見えている値」をログに集約する発想(擬似コード)
# 実際の回避目的ではなく、テスト観点の整合性確認として利用してください。
result = {
"http_headers": captured_request_headers,
"js": {
"userAgent": page.evaluate("() => navigator.userAgent"),
"uaData": page.evaluate("() => navigator.userAgentData"),
"languages": page.evaluate("() => navigator.languages"),
"timeZone": page.evaluate("() => Intl.DateTimeFormat().resolvedOptions().timeZone"),
"screen": page.evaluate("() => ({w: screen.width, h: screen.height, dpr: devicePixelRatio})")
}
}
print(result)注意
「値を偽装して突破する」こと自体が、サイト利用規約や法令、セキュリティポリシーに抵触する可能性があります。業務で行う場合は、対象サイトの許諾・契約条件・社内コンプライアンスを必ず確認してください。
まとめ
- ブラウザ指紋の「矛盾」は、単一値よりも偽装コストが高く、検知シグナルとして強い
- 特に UA / UA-CH / navigator.userAgentData の不整合は目立ちやすい
- 整合性チェックはルールベースとスコアリングの併用が現実的
- 対策・検証では、観測点の棚卸し→基準プロファイル→差分最小化が基本