スクレイピング

TLSフィンガープリント(JA3/JA4)検出の仕組みと見抜かれるポイント

JA3/JA4はTLS ClientHelloから生成されるフィンガープリントで、WAF/CDNのボット検出に利用されます。本記事では仕組み、見抜かれるズレ(UA不一致・ALPN・拡張)、検証手順と実務の注意点を整理します。

Ibuki Yamamoto
Ibuki Yamamoto
2026年2月27日 12分で読めます

TLSフィンガープリント(JA3/JA4)検出の仕組みと見抜かれるポイント

JA3/JA4は「TLSハンドシェイクの最初に送られるClientHello(平文で観測できる部分)」から、クライアント実装の癖を要約して識別する仕組みです。IPやCookieを変えてもTLSスタックが同じなら痕跡が残りやすく、特にスクレイピングや自動化ではボット判定の重要シグナルになり得ます。本記事では、JA3/JA4の作られ方、実運用で検出される典型パターン、そして“見抜かれるズレ”の具体例を整理します。

この記事でわかること
  • JA3/JA4がClientHelloから作られる仕組み
  • ボット検出で見られるズレと観測ポイント
  • スクレイピング側での実務的な対処の考え方

JA3/JA4とは

JA3は2017年にSalesforceの研究者らが提案した、TLSクライアントのフィンガープリント手法です。TLS接続開始時、クライアントはServerと暗号化通信を始める前にClientHelloを送りますが、この中の「TLSバージョン」「暗号スイート」「拡張」「楕円曲線(グループ)」「ポイントフォーマット」などの組み合わせが、実装(ブラウザ、TLSライブラリ、OS)ごとに偏ります。JA3はそれらの数値列を連結し、MD5でハッシュ化して識別子にします。公式実装の説明でも、対象フィールドと文字列化ルール(カンマ区切り・ハイフン区切り)が明確に示されています。

一方JA4(JA4+)は、JA3の課題(特に近年のTLS 1.3環境での識別の難しさや、実装差の出にくさ)を踏まえて設計された後継系のフィンガープリント群です。FoxIOの解説では、JA4はClientHelloを観測して「人間にも機械にも扱いやすい」形式のフィンガープリントを作る、と説明されています。またCloudflareのドキュメントでも、JA4はClientHello拡張をソートするなどして、現代ブラウザで増えがちな“過剰にユニークな指紋”を減らす方向性が言及されています。

重要:JA3/JA4は「HTTPヘッダやUser-Agent」より手前のTLS層で観測されます。つまり、ヘッダをChromeっぽく整えても、TLSの指紋がPython/Go/古いOpenSSLのままだと矛盾が出やすい、という点が肝です。

仕組みの全体像

ClientHelloが鍵

TLSの最初のメッセージであるClientHelloには、暗号化方式の候補や拡張の要求が並びます。TLS 1.3仕様(RFC 8446)でも、たとえば鍵共有に使うグループ(supported_groups)をクライアントが宣言し、優先順で並べることが定義されています。こうした「何を」「どの順で」「どの値で」送るかが、指紋になります。

JA3の生成要素

JA3は、ClientHelloから以下のような値を抽出して文字列化します(概念レベルの整理です)。

  • TLS/SSL Version
  • Cipher Suites(暗号スイートの列)
  • Extensions(拡張の列)
  • Elliptic Curves / Named Groups(楕円曲線・グループ)
  • Elliptic Curve Point Formats

この文字列をMD5にかけたものが、いわゆるJA3ハッシュです。SalesforceのJA3リポジトリでは、連結フォーマットや例が具体的に示されています。また、GREASE(拡張性テストのためのランダム値)を無視して安定させる実装上の配慮も説明されています。

JA4の狙い

JA4はClientHelloを基にしつつ、より構造化された形式(a_b_c)を採用し、ALPN(例えばh2/h1など)なども読み取りやすく取り込みます。FoxIOの説明では、HTTP/3(QUIC)も含めてクライアントを指紋化できる点が強調されています。さらにCloudflareの説明では、ClientHello拡張をソートすることで、実装差のノイズを減らす方向が示されています。

見抜かれるポイント

TLSとUAの不一致

最も典型的なのが「User-AgentはChromeなのに、TLS指紋がそれっぽくない」ケースです。例えば、HTTPヘッダはブラウザ風でも、TLSがrequests/OpenSSL由来のままだと、エッジ側(CDN/WAF)では簡単に矛盾として扱えます。実際、CloudflareはBot ManagementでJA3/JA4を扱えることを明記しており、ルールや分析基盤に統合できます。

ALPNが不自然

JA4ではALPN(次に話したいアプリ層プロトコル)も読み取りやすい要素として扱われます。FoxIOの解説では、ALPN “h2”はHTTP/2を希望していることを意味し、“00”はALPNが無いことを示す、と説明されています。ブラウザを装うのにALPNが欠けている、あるいはHTTP/2を使うはずがHTTP/1.1しか出ていない、といったズレは疑われやすいポイントです。

拡張の組み合わせと順序

JA3は(設計上)値の「順序」に敏感です。そのため、ライブラリ更新やOS差、環境差で指紋が揺れたり、逆に攻撃側が順序を調整して回避したりという駆け引きが起きます。nDPI(ntop)の記事でも、JA3は順序依存で“壊れやすい”ことが課題として触れられています。JA4が拡張のソートなどを取り入れる背景には、こうした脆さの緩和があります。

TLS 1.2固定・古い暗号

運用の現場では、古いTLSバージョンや暗号スイートの偏りが、そのまま“自動化ツールっぽさ”として扱われることがあります。もちろん古い実装の正当なクライアントも存在しますが、ターゲットサイトの一般ユーザ分布と比べて不自然だと、リスクスコアが上がる要因になります。

注意:本記事は検出の仕組みを理解し、正当な自動化(負荷配慮、規約遵守、認証連携など)を設計するための技術解説です。アクセス制限の回避そのものを目的にすると、利用規約違反や不正アクセスに該当するリスクが高まります。

検出側の運用像

WAF/CDNでの利用

検出側は、JA3/JA4を単体で決め打ちするというより、他シグナルと組み合わせて使います。CloudflareはJA3/JA4を分析(Analytics/Logs)や制御(WAFルール、Workers等)に利用できることを明記しています。つまり「同じJA3/JA4から短時間に大量アクセス」「特定JA3だけに不正ログインが集中」といった相関で使われます。

ホワイトリストにも使える

意外に見落とされがちですが、JA3/JA4は“許可”にも使えます。Cloudflareの例でも、モバイルアプリが同じJA3を返しやすい点を活かし、アプリ由来トラフィックを判別して許可するユースケースが示されています。

スクレイピングの対処

狙うのは整合性

正直に言うと、フィンガープリント対策の本質は「特定の値を偽装する」より「振る舞い全体の整合性を取る」ことです。TLS指紋、HTTPヘッダ、HTTP/2利用、Cookie/セッション、リダイレクトの辿り方、JS実行の有無が噛み合っているかが見られます。

実装の選び方

対処の方向性は大きく2つです。

  1. ブラウザ自動化(Playwright等)で“本物のブラウザTLSスタック”に寄せる
  2. HTTPクライアントでも、ブラウザ近似のTLSシグネチャを出せる実装を選ぶ

後者の例として、curl_cffi系の実装を使い、特定ブラウザのTLSシグネチャを模倣するアプローチがコミュニティで共有されています(ただし採用判断は自己責任で、対象サイト規約と用途の正当性を必ず確認してください)。

観測と検証の手順

現場での改善は、以下のように“見える化”から始めるのが定石です。

  1. 自社クライアントのJA3/JA4を計測する(検証環境で)
  2. 想定ブラウザのJA3/JA4と差分を取る
  3. ALPN、HTTP/2、TLSバージョンの整合性をチェック
  4. ブロック条件(WAFログ、チャレンジ発火点)と突合

単に「IPを回す」だけでは改善しないケースが多いのは、JA3/JA4がIP変更の影響を受けにくい(クライアント実装に依存する)ためです。

最小コード例

ここでは“何が指紋になっているか”を理解するため、Wireshark等でClientHelloを観測する前提の補助として、TLS接続を作る最小例を示します(このコード自体がブラウザ同等の指紋を出すわけではありません)。

import ssl
import socket

host = "example.com"
ctx = ssl.create_default_context()

with socket.create_connection((host, 443)) as sock:
    with ctx.wrap_socket(sock, server_hostname=host) as ssock:
        print("TLS version:", ssock.version())
        print("Cipher:", ssock.cipher())

重要:実際のJA3/JA4は、ここで表示する暗号スイートの“結果”ではなく、ClientHelloで提示した候補(リスト)や拡張の集合・並びなどから作られます。計測は「ClientHelloの生パケット」またはエッジログで行うのが確実です。

参考リンク

仕様・公式説明として、以下を参照してください。






収集設計を相談しませんか?

JA3/JA4を含む検出シグナルは複合評価されます。目的と制約に合わせた収集設計・負荷設計を一緒に整理しましょう。

お問い合わせスクレイピングに関するご相談・お見積もりはお気軽にどうぞ
相談する

まとめ

  • JA3/JA4はTLS ClientHello(暗号化前に観測できる)から作られる指紋で、IPを変えても残りやすい
  • 見抜かれる要点は「TLS指紋とUA/HTTP挙動の不一致」「ALPNや拡張の不自然さ」「古いTLS特性」
  • 対策は“偽装”より“整合性”が中心で、計測→差分→ログ突合のサイクルが有効

この記事を書いた人

Ibuki Yamamoto
Ibuki Yamamoto

Webスクレイピングエンジニア。10年以上の実務経験を持ち、大規模なデータ収集プロジェクトを数多く手がける。PythonとJavaScriptを得意とし、技術ブログでは実践的なスクレイピング手法を発信している。

データ収集のプロに
お任せください

年間1億件以上のデータ収集実績を持つプロフェッショナルチームが、大規模スクレイピング・アンチボット対策など、あらゆる課題を解決します。

1億+
年間データ収集件数
24/7
安定稼働
高品質
データ精度