「〇〇の顧客データ2,400万件を400ドルで売る」——ダークウェブの販売告知は、件数と価格だけが先に広まります。けれども件数も中身も出どころも、販売者の申告でしかありません。2026年10月16日のメルカリの事案でも、告知を伝えた投稿自身が「未検証」と書き、サンプルについては「分析用のデータに見える」と「生成AIで作った偽物の可能性が高い」という2つの見方が出ました。
連載「事故から逆算するWebセキュリティ」の第17回は、こうした告知を企業と利用者がどう読むかを扱います。盗まれたデータは手に入れず、自社のデータモデルと照合する小さなスクリプトを合成データで試しました。攻撃の入口側の全体像は サプライチェーン攻撃とは|手口・防御ツール比較・npm 12の新機構まで実践解説 にまとめています。
CLAIM VS CHECK告知と確かめること
件数と価格ではなく、自社のデータの形と合うかで読む
販売告知に書かれること
すべて販売者の申告
- 件数(例: 2,400万件)と価格
- 含むとされる項目の一覧
- 数行〜数百行のサンプル
当事者が確かめること
データを買わずにできる
- 列の形と社内専用の列
- IDの形式と実在、日付の範囲
- カナリア行が混ざっていないか
30秒でわかる
- ・件数は信頼度を示さない:古いデータの再販、公開情報の寄せ集め、作ったサンプルも同じ形で告知される
- ・真偽を決められるのは当事者だけ:自社のデータモデルと照合できるのは、データを持つ企業だけ
- ・買わずに読む:列の形・社内専用の列・IDの形式と実在・日付の範囲・カナリア行を、公開されたサンプルで照合する
- ・利用者はなりすましに備える:真偽が出る前でも、そのサービスを名乗る偽の連絡は増えやすい
ダークウェブの販売告知は、なぜそのまま信じられないのか
メルカリの事案のタイムラインは、メルカリ情報漏洩の主張|2,400万件のデータ販売は未確認、分かっていることと利用者の備え に整理しました。要点だけ引くと次のとおりです(いずれも当サイトの同記事の確認範囲)。
| 日時(日本時間) | 出来事 |
|---|---|
| 2026-10-16 0:05 | Dark Web Informer が、販売者「tet」がメルカリの2,400万件を400ドルで売ると主張していると投稿。投稿自身が「主張は未検証」と書く |
| 10-16 9:51 | Aikido Community Japan が、列に snapshot_date と集計項目が並び、BI・DWH の形に近いと投稿(真偽は不明と断ったうえで) |
| 10-16 | セキュリティ対策Lab が、サンプルは生成AI製で嘘の可能性が非常に高いとする記事を公開(同記事では見出しのみ確認) |
2つの見方は矛盾していません。前者は「本物だとしたら、どの系統から出た形か」、後者は「そもそも本物か」を見ています。どちらも、外から見えるサンプルの形を手がかりにしている点が同じです。
販売告知には、本物の流出のほかに次のようなものが混ざります。
・再販:数年前に流出したデータに、新しい日付と大きな件数をつけ直したもの
・寄せ集め:別々の流出や公開情報から、同じサービスの利用者らしい行を集めたもの
・作り物:それらしい列名と値を作ったサンプルで、買い手や注目を集めるもの
流出データの照合サービス Have I Been Pwned(HIBP)も、登録する事案を「確認済み」「未確認」「作り物(fabricated)」「スパム用のリスト」に分けています。API の説明では、作り物の事案は「名指しされたサイトから取られた可能性が低く、作られたデータを多く含むが、実在するメールアドレスも含む」とされています。実在のメールアドレスが入っていることは、そのサービスから漏れた証拠になりません。
サンプルを買わずに読む6つのシグナル
販売者が見せるサンプルや列の一覧は、多くの場合、告知や転載の画像に写っています。当事者はそれを自社の設計と照らし合わせるだけで、かなりのことが分かります。
| シグナル | 何を示唆するか | 注意 |
|---|---|---|
| 列の構成が自社のデータモデルと合う | 自社の系統から出た可能性。本番DBか分析基盤かの見当もつく | 一般的な列名(email・phone)だけの一致は弱い |
| 画面にもAPIにも出さない社内専用の列がある | 内部のデータに触れた可能性が高い | 列名を推測で付けた作り物でないか、値の形まで見る |
| IDの形式が合い、自社に実在する | 実データに由来する可能性が高い | 公開プロフィールのIDなら外から集められる |
| 日付がサービス開始前・未来に及ぶ | 作り物のしるし | 移行データの古い日付は説明がつくことがある |
| 最新の日付が古い時点で止まっている | いつ時点のデータか。過去の流出の再販を疑う | 分析基盤の取り込みが止まっている系統の可能性もある |
| 仕込んだカナリア行が混ざっている | 出どころが自社だとほぼ確定 | 仕込んでいなければ使えない。後述の設計が前提 |
このほか、販売者の過去の取引や評判も判断材料になります。ただし掲示板の評判は外から確かめにくく、当サイトでは扱える情報を持っていません。脅威情報の調査を業務にしている事業者の報告に頼る部分です。
合成データで試す:告知のサンプルを自社のデータモデルと照合する
上の表の6つのシグナルを機械で出すスクリプトを書き、すべて自作の合成データで試しました。自社の利用者表(5,000行+カナリア2行)を作り、そこから3種類の「告知のサンプル」を作っています。
・陽性:自社の行から200行を抜き、カナリア1行と社内専用の列 fraud_score を含むもの
・陰性:列名・ID形式・日付をそれらしく作った、自社とは別物の200行
・再販の想定:自社の行だが、2022年末までに登録した利用者だけの200行
# assess_claim.py — 販売告知のサンプルを、自社のデータモデルと突き合わせる(盗まれたデータは入手しない前提)
import csv, json, re, sys, datetime as dt
schema = json.load(open(sys.argv[1]))
own = {r[schema["id_column"]]: r for r in csv.DictReader(open(sys.argv[2]))}
rows = list(csv.DictReader(open(sys.argv[3])))
norm = lambda c: re.sub(r"[^a-z0-9]", "", c.lower())
cols = {norm(c): c for c in rows[0]}
print(f"サンプル: {len(rows)}行 / 列 {list(rows[0])}")
# 1. 列の一致:どの系統(本番DB・分析基盤)の形に近いか
for src, fields in schema["sources"].items():
hit = [f for f in fields if norm(f) in cols]
print(f"列の一致 {src}: {len(hit)}/{len(fields)}")
# 2. 社内でしか持たない列(画面にもAPIにも出さない列)
inside = [f for f in schema["internal_only"] if norm(f) in cols]
print(f"社内専用の列: {inside or 'なし'}")
# 3. IDの形式と、自社に実在するか(メールまで一致するか)
idc = cols.get(norm(schema["id_column"]))
ids = [r[idc] for r in rows] if idc else []
fmt = sum(bool(re.match(schema["id_regex"], i)) for i in ids)
real = sum(i in own and own[i]["email"] == r.get(cols.get("email", ""), "") for i, r in zip(ids, rows))
print(f"ID形式の一致: {fmt}/{len(rows)} / 実在して列も一致: {real}/{len(rows)}")
# 4. 日付の範囲:サービス開始前・未来の日付は作り物のしるし。最新日は「いつ時点のデータか」
dc = cols.get(norm(schema["date_column"])) or next((c for k, c in cols.items() if "date" in k), None)
if dc:
ds = sorted(r[dc] for r in rows)
bad = sum(d < schema["launched"] or d > dt.date.today().isoformat() for d in ds)
print(f"日付 {dc}: {ds[0]}〜{ds[-1]} / 範囲外 {bad}件")
# 5. カナリア(ハニートークン):実在しない行が1件でも出たら、自社のデータが出た強い証拠
can = [v for r in rows for v in r.values() if v in schema["canaries"]]
print(f"カナリア: {can or 'なし'}")
own_schema.json には、系統ごとの列(本番DBの prod.users と分析基盤の dwh.user_daily)、社内専用の列、IDの正規表現、サービス開始日、カナリアのIDとメールを書いておきます。3つのサンプルに当てた結果です(2026年10月17日、Python 3.13.16)。
$ for s in positive fabricated recycled; do python3 assess_claim.py own_schema.json own_users.csv claim_$s.csv; done
サンプル: 200行 / 列 ['user_id', 'EMAIL', 'display_name', 'phone', 'prefecture', 'created_at', 'fraud_score']
列の一致 prod.users: 7/8
列の一致 dwh.user_daily: 2/6
社内専用の列: ['fraud_score']
ID形式の一致: 200/200 / 実在して列も一致: 200/200
日付 created_at: 2019-06-19〜2026-10-14 / 範囲外 0件
カナリア: ['U7c1a9e0d4b22', '[email protected]']
サンプル: 200行 / 列 ['id', 'full_name', 'email', 'phone_number', 'address', 'signup_date', 'total_sales']
列の一致 prod.users: 1/8
列の一致 dwh.user_daily: 0/6
社内専用の列: なし
ID形式の一致: 0/200 / 実在して列も一致: 0/200
日付 signup_date: 2016-01-07〜2027-12-29 / 範囲外 73件
カナリア: なし
サンプル: 200行 / 列 ['user_id', 'email', 'display_name', 'prefecture', 'created_at']
列の一致 prod.users: 5/8
列の一致 dwh.user_daily: 2/6
社内専用の列: なし
ID形式の一致: 200/200 / 実在して列も一致: 200/200
日付 created_at: 2019-04-08〜2022-12-28 / 範囲外 0件
カナリア: なし
| サンプル | 列の一致(本番DB) | 社内専用の列 | ID形式・実在(200行中) | 日付 | カナリア | 読み方 |
|---|---|---|---|---|---|---|
| 陽性 | 7/8 | あり | 200・200 | 範囲内 | 1行 | 自社から出たと判断できる |
| 陰性(作り物) | 1/8(email だけ) | なし | 0・0 | 73件が範囲外 | なし | 作り物の可能性が高い |
| 再販の想定 | 5/8 | なし | 200・200 | 2022-12-28で止まる | なし | 実データだが古い。過去の流出と突き合わせる |
陽性は列名の EMAIL を大文字にしてありますが、列名を正規化して照合しているので一致に数えています。3つ目のように実データでもカナリアが出ないことはあり、カナリアが無いことは「自社のものではない」証拠になりません。最新の日付が止まっている時点は、その頃の流出やバックアップ、分析基盤への書き出しを洗い直す手がかりになります。
対策:ダークウェブで自社の名前が出たときの企業側の手順
FIRST RESPONSE企業側の手順
買わずに保全し、照合してから連絡と報告を決める
-
01
買わない・接触しない
告知のURL・画面・日時を記録して保全
-
02
データモデルとログで照合
列・ID・日付・カナリアと、その期間の大量の読み出し
-
03
連絡と報告の準備
利用者向けの文面と「おそれ」の判断を法務と
・買わない・接触しない:代金は犯罪の資金になり、本物かどうかも買うまで分かりません。告知のURL・画面・日時を記録して保全します
・データモデルと照合する:前の節のシグナルを、公開されているサンプルと列の一覧だけで確かめます。どの系統(本番DB・分析基盤・外部委託先への受け渡し)の形に近いかで、調べる場所が絞れます
・その期間のログを見る:日付が止まった時点の前後で、大量の読み出し・書き出し、普段使わない認証情報の利用がないかを見ます
・連絡と報告を準備する:真偽が出る前でも、利用者向けの注意喚起の文面と問い合わせ窓口を用意します
報告の要否は、個人情報保護委員会の「漏えい等報告・本人への通知の義務化について」の考え方で整理します。同委員会の資料では、要配慮個人情報・財産的被害のおそれ・不正の目的・1,000人超の4類型で、漏えいが確定していなくても「おそれ」がある段階で報告と本人への通知の対象になり得るとされています。おそれの判断は、その時点で分かっている事実をもとに個別に行うとされ、速報は知った日から概ね3〜5日以内、確報は30日以内(不正の目的によるおそれがあるものは60日以内)とされています。告知が出ただけで報告対象になるかは事実関係しだいなので、照合の結果を持って法務と決めます。
企業が自ら調べて発表した事案では、件数や範囲が企業の調査として示されます。ソースネクスト情報漏洩|最大2,252万件・パスワードも対象、会員とAPIを持つ側が確認すること は、その形の例です。販売告知だけの段階とは、判断の材料の重さが違います。
カナリア行(ハニートークン)で、流出を自分で知れる設計にする
前の節の照合で最も強いシグナルは、カナリア行の一致でした。カナリア行(ハニートークンの一種)は、実在しない利用者の行をデータベースに置き、どの画面にもAPIにも出さないようにしておくものです。正規の経路では外に出ないので、その行が販売サンプルやスパムの宛先に現れたら、データが自社から出たとほぼ言えます。
CANARY RECORD流出を知る仕掛け
実在しない利用者の行が外で見つかれば、出どころは自社
-
架空の行を置く
固有のメール・ID
-
画面・APIに出さない
正規の経路では届かない
-
外に出る
販売サンプル・スパム
-
照合で一致
メール受信・照合で通知
Thinkst の Canarytokens のドキュメントは、固有のメールアドレスを発行し、USERS 表に偽の行として置いておく使い方を例に挙げています。そのアドレスにメールが届けば、誰かがデータに触れたと分かる仕組みです。同じドキュメントには、MySQL のダンプに埋め込むものや、決済情報の置き場に置くクレジットカード型もあります。
設計で気をつけることは次のとおりです。
・系統ごとに別のカナリアを置く:本番DB・分析基盤・バックアップ・委託先への受け渡しで変えておけば、どこから出たかまで分かる
・集計や通知から外す:利用者数の集計、メール配信、不正検知の学習データに混ぜない
・存在を知る人を絞る:一覧は照合する担当だけが持ち、社内の誰でも引ける場所に置かない
利用者のチェックリストと、影響範囲の見方
利用者が販売告知の真偽を確かめる手段はありません。真偽にかかわらず、話題になった時点でそのサービスを名乗る偽の連絡が増えやすいので、次の3点で備えます。
・リンクを開かない:「流出の確認はこちら」といったメールやSMSのリンクは踏まず、公式アプリか自分で入力したURLから確かめる
・使い回しを先に断つ:同じパスワードを他のサービスで使っているなら、そちらを先に変える
・公式の発表で判断する:転載記事の多くは同じ1本の投稿を引いている。数字が増えて見えても、元が1つのことがある
影響範囲は、告知の件数ではなく、企業が照合して示す範囲で考えます。告知が「2,400万件」と言っても、本物の部分が一部だけのことも、すべて作り物のこともあります。企業側も、照合で分かったことと分かっていないことを分けて発表すれば、利用者は自分が対象かを判断しやすくなります。
参照ソース
- メルカリ情報漏洩の主張|2,400万件のデータ販売は未確認、分かっていることと利用者の備え(当サイト。事案の経緯と2つの見方、各ソースの確認範囲はこの記事による)
- wneessen/go-hibp breach.go(HIBP API v3 の Breach モデルの説明を写したコメント。commit 001684d で確認)
- Have I Been Pwned API v3(公式の説明。上のクライアントで確認)
- 個人情報保護委員会「漏えい等報告・本人への通知の義務化について」(最新の内容は同ページとガイドライン(通則編)で確かめてください)
- Thinkst Canarytokens ドキュメント「Unique email address Canarytoken」(GitHub 上の原文を commit 0fbbebf で確認)





