title: “1,418文字の視覚的欺瞞:Unicode混同攻撃の実態とSSIMで見える「本当に危険な82文字ペア」”
date: 2026-02-26
category: Security
tags: unicode, security, homoglyph, ssim, visual-attack
—
はじめに:見えない脅威
Web開発者は皆、「SQLインジェクション」や「XSS」といった攻撃には馴染みがあるだろう。だが、「視覚的な類似性」を悪用する攻撃についてはどうだろうか?
例えば、この2つのドメインを見分けられるだろうか?
gοοgle.com(ギリシャ文字ο)google.com(ラテン文字o)
一見して同じに見える。だが、前者はフィッシングサイトかもしれない。このような攻撃は「Homoglyph Attack(同形文字攻撃)」と呼ばれ、Unicodeの膨大な文字セットが温床となっている。
2026年2月、開発者Paul Tendoが1,418組のUnicode混同文字ペアを230種類のフォントで実際にレンダリングし、SSIM(Structural Similarity Index Measure)を使って定量化する実験を行った。その結果は衝撃的だった。
96.5%の混同文字ペアは実際には危険ではない。
だが、82ペアは「ピクセルレベルで完全に同一」だった。
本記事では、この実験の詳細と、Web開発者が知るべき実践的対策を解説する。
—
What:Unicode混同文字攻撃とは
Unicode Consortiumは、世界中の文字体系を統一的に扱うための標準を策定している。現在、Unicodeには15万文字以上が含まれている。
その中には、視覚的にほぼ同じに見えるのに、異なるコードポイントを持つ文字が多数存在する。これらは「Confusables(混同文字)」としてUTS #39で文書化されている。
主な混同文字の例
| 正規文字 | 混同文字 | スクリプト | 例 |
|———|———|———–|—–|
| a | а | キリル文字 | pаypal.com |
| e | е | キリル文字 | еmail.com |
| o | ο | ギリシャ文字 | gοοgle.com |
| 0 | О | キリル文字 | О0 |
| l | ӏ | キリル文字 | ӏogin |
これらを悪用した攻撃パターン:
—
How:実験手法
confusable-visionツール
Paul Tendoは、この問題を定量化するためにconfusable-visionというツールを開発した。
処理フロー:
1,418混同文字ペア
↓
fontconfigで文字対応フォントを検索
↓
8,881回のターゲットレンダリング(48×48グレースケールPNG)
↓
235,625回のSSIM比較
↓
スコア付きJSON出力
なぜSSIMなのか
SSIM(Structural Similarity Index Measure)は、2つの画像の類似性を測る指標で、-1から1の値を返す:
- 1.0: ピクセル完全同一
- 0: 構造的相関なし
- -1: 反相関(ランダムノイズより似ていない)
学習ベースのCNN(VGG16など)ではなくSSIMを採用した理由は明確だ:再現性。GPUも学習データもモデル重みも不要。誰でも同じ結果を再現できる。
フォント発見
230種類のシステムフォントを使用:
| カテゴリ | 数 | 用途 |
|———|—–|——|
| standard | 74 | Latin主要フォント(Arial, Menlo, Georgia等) |
| script | 49 | CJK、Indic、Thai等のラテン文字含有フォント |
| noto | 103 | 非ラテンスクリプト用Noto Sans |
| math | 3 | STIX Two Math等 |
| symbol | 1 | Apple Symbols |
—
Results:衝撃の統計
ヘッドライン:96.5%は危険ではない
| バンド | 数 | % | 説明 |
|——-|—–|—–|——|
| High (>= 0.7) | 49 | 3.5% | 本当に危険 |
| Medium (0.3-0.7) | 681 | 48.0% | フォント依存 |
| Low (< 0.3) | 611 | 43.1% | 視覚的に混同不可 |
| No data | 77 | 5.4% | システムフォントに存在せず |
中央値SSIM: 0.322 — 典型的な混同文字は、実際にはあまり似ていない。
だが82ペアはピクセル完全同一
平均SSIMは脅威を過小評価する。攻撃者は「少なくとも1つのフォント」で成功すればよい。
例:キリル文字ԁ (U+0501) とラテン文字d
- 平均SSIM: 0.781(中程度)
- しかし8つのフォントでSSIM 1.000(ピクセル完全同一)
Arial, Menlo, Cochin, Tahoma, Charter, Georgia, Baskerville, Verdana — これら全てで完全に区別不可能。
最も危険なスクリプト
#### キリル文字ホモグリフ:真の脅威
キリル文字はラテン文字と多くの共通グリフを持つ。一部は同一のグリフを共有:
- а → a
- е → e
- о → o
- р → p
- с → c
- х → x
これらは履歴的に同一のグリフから派生したため、多くのフォントで完全に区別不可能。
#### ローマ数字:意図的なグリフ再利用
ローマ数字(Ⅰ, Ⅱ, Ⅲ等)は多くのフォントでラテン文字Iと同じグリフを使用。これはバグではなく、設計上の決定。
#### ヘブライ語Paseq:予期せぬ発見
ヘブライ語のPaseq(U+05C0)は、一部のフォントでラテン文字の縦棒(|)と完全に同一にレンダリングされる。これは予期せぬ発見だった。
—
最も危険なフォント
高危険率フォント
フォントによって危険度が大きく異なる。一部のフォントは混同文字ペアの20%以上をピクセル同一でレンダリングする。
低危険率フォント
逆に、一部のフォントは混攻撃に対して非常に堅牢。独自のタイポグラフィックデザインが、異なるスクリプト間の視覚的差異を保持している。
—
Web開発者への実践的対策
1. IDN(国際化ドメイン名)の検証
// Punycode形式に変換して確認
function checkDomain(domain) {
const punycoded = punycode.toASCII(domain);
if (punycoded !== domain) {
console.warn('非ASCII文字が含まれています:', punycoded);
}
}checkDomain('gοοgle.com'); // xn--ggle-6qda.com
2. ユーザー名の正規化
// UTS #39準拠の正規化
const { confusables } = require('unicode-confusables');function normalizeUsername(username) {
return username.normalize('NFKC')
.split('')
.map(char => confusables.get(char) || char)
.join('');
}
normalizeUsername('pаypal'); // 'paypal'(キリルа → ラテンa)
3. 視覚的警告の実装
// 混在スクリプト検出
function detectMixedScript(text) {
const scripts = new Set();
for (const char of text) {
const script = getScript(char); // Unicodeスクリプト判定
scripts.add(script);
}
if (scripts.size > 1) {
return {
warning: '複数の文字体系が混在しています',
scripts: Array.from(scripts)
};
}
return { safe: true };
}
4. フォント選択の考慮
危険率の低いフォントを優先的に使用。特に、ユーザー生成コンテンツを表示する領域では、フォント選択がセキュリティ上の決定となり得る。
—
Why:なぜこの問題は解決されないのか
互換性 vs セキュリティ
Unicodeの歴史的互換性要件により、多くの「同一グリフ・異なるコードポイント」が標準化されている。これを変更すると、膨大な既存データが破損する。
TR39の限界
UTS #39のconfusables.txtは視覚的類似性を主張しているが、大規模な実証検証は行われてこなかった。多くのエントリはNFKC正規化下での意味的マッピングに基づいており、実際のレンダリング結果とは乖離がある。
フォント依存性
同一の文字でも、フォントによって全く異なるグリフでレンダリングされる。Webアプリケーションはエンドユーザーのフォントを制御できないため、完全な対策は困難。
—
When:攻撃が成功する状況
—
Where:影響範囲
- Webブラウザ: ドメイン、URLパラメータ、フォーム入力
- SNS: ユーザー名、ハッシュタグ、メンション
- メッセージングアプリ: 送信者名、グループ名
- コードエディタ: 変数名、関数名、識別子
- 決済システム: 口座名義、送金先
—
Conclusion:見えない脅威への対策
Paul Tendoの実験は、Unicode混攻撃の実態を初めて大規模に定量化した。重要な知見:
推奨アクション
視覚的欺瞞は「見えない」攻撃だが、適切な対策で可視化し、無力化できる。開発者は今こそ、Unicodeの深淵を理解し、ユーザーを守る準備をすべきだ。
—
参考リンク
- confusable-vision GitHub
- UTS #39: Unicode Security Mechanisms
- Unicode Confusables Data
- Paul Tendo’s Blog Post
—
*この記事はReddit r/programmingで話題の投稿を基に、技術的背景と実践的対策を深掘りして執筆しました。*


コメント