日本語

開発者ツール · URL エンコーダーとデコーダー

Punycode とパーセント エンコーディング: 非 ASCII ドメインとパスの処理方法

· 背景

国際化 ピュニコード URLエンコーディング

パスはパーセントエンコードされたままで、ドメイン名が Punycode に変換されます
オリジナル ToolAcre ベクトル イラスト

非 ASCII ホスト名と非 ASCII パスを持つ URL は、2 つの完全に異なるエンコーディングを使用します。この記事では、ホストの IDNA と Punycode、その他すべてのパーセント エンコーディング、および分割が存在する理由について説明します。

あるブラウザーでは「münchen.example」を表示し、別のブラウザーでは「xn--mnchen-3ya.example」を表示するアドレス — 1 つのホスト、2 つのスペル

ミュンヘンという都市はドイツのドメイン名に表示されます。ブラウザのアドレス バーに、münchen.example が正常に表示されることがあります。別のアプリケーションからアドレスをコピーすると、xn--mnchen-3ya.example として表示されます。これはドイツ語のテキストとはまったく異なる ASCII のみの文字列です。 1 つの URL、2 つのスペル、どちらも完全に有効です。どちらも間違いではありません。これらは、まったく異なる文字セットを使用して同じドメインを表します。この違いは、DNS の動作方法と、インターネット インフラストラクチャがホスト名の送信をどのように期待するかに関する基本的な制約を反映しています。

/café/ のようなパス セグメントはエンコードが必要ですが、別のシステムを使用します。非 ASCII é はパス内では %C3%A9 になります。なぜ違いがあるのでしょうか? DNS 制約では、ホスト名に Punycode が必要です。

ホスト名でパーセント エンコーディングを使用できない理由 — DNS ラベル、許可される文字、および長さの制限

DNS ラベル (ドットで区切られたホスト名の個々のセグメント) には、非常に厳密なルールがあります。 ASCII 文字、数字、ハイフン、アンダースコアのみを含めることができます。これらには長さの制限があります。各ラベルは最大 63 オクテットにすることができ、完全なホスト名は 255 オクテットを超えることはできません。これらは DNS プロトコル自体による厳しい制約であり、国際ドメイン名が概念になる数十年前に定義されました。結果の文字列が長い単語のラベル制限を超える可能性があるため、パーセント エンコーディングはホスト名に対しては機能しません。

さらに重要なのは、DNS は世界中のルーターとサーバーによって運用されるグローバル システムであるということです。それらのすべてが UTF-8 や Unicode を理解できるわけではありません。 %C3%A9 のようなパーセントでエンコードされた文字は 3 つの ASCII 文字であるため、DNS の制約に適合します。しかし、このアプローチでは、すべてのルックアップで受信時にパーセント エンコードし、出力時にデコードする必要があることを意味し、プロトコル層自体が複雑になります。特にホスト名については、より良いソリューションが必要でした。

IDNA と Punycode の概要 - xn-- プレフィックスとブートストリング アルゴリズム (定性的に説明)

IDNA (アプリケーションにおける国際化ドメイン名仕様) は、非 ASCII ドメイン名を DNS が処理できる ASCII にエンコードすることでホスト名の問題を解決します。使用されるエンコーディングは、punycode と呼ばれます。これは、プレフィックス xn-- の後にブートストリングでエンコードされた表現を使用して、Unicode テキストを ASCII に変換する圧縮アルゴリズムです。アルゴリズムは決定的です。münchen は毎回常に xn--mnchen-3ya になります。 DNS 解決を行う前に、非 ASCII ホスト名をこの方法で変換する必要があります。

xn-- プレフィックスは、DNS および IDNA 対応ソフトウェアに、次の文字がリテラルの ASCII 文字ではなく Punycode であることを知らせます。 example.xn--mnchen-3ya.com のようなドメインは、IDNA 対応ソフトウェアでは example.münchen.com を意味すると理解されます。 Punycode は ASCII 文字、数字、ハイフンのみを使用するため、DNS ラベルに問題なくきれいに適合します。このアルゴリズムは、非 ASCII 情報をこの ASCII 表現に圧縮します。

パス、クエリ、およびフラグメントはパーセント エンコードされたままになります — 他の場所と同様に、UTF-8 バイトが %XX になります

URL 内の他のすべて (パス、クエリ文字列、フラグメント) では、代わりにパーセント エンコーディングが使用されます。非 ASCII 文字はまず UTF-8 バイトに変換され、次に各バイトが %HH (HH は 16 進数) として書き込まれます。パス /café/ は /caf%C3%A9/. になります。 クエリ文字列 ?name=josé は ?name=jos%C3%A9 になります。パーセント エンコーディングは、HTTP リクエスト URL、HTML フォーム、API など、Web 上のどこでも標準です。 DNS やルーターによる特別な処理は必要ありません。

パーセント エンコーディングを使用すると、他の特殊文字も安全に表現できます。スペースは %20 になり、スラッシュ (値の中に使用する必要がある場合) は %2F になります。この計画は一貫性があり、普遍的です。 DNS は URL やパーセントエンコーディングを理解できないため、ホスト名には使用されません。 ASCII ラベルのみを理解します。

成功した例: 両方を含む 1 つの URL — ホストが Punycode に変換され、パスがパーセントでエンコードされ、並べて表示されます。

URL「https://münchen.example/café?city=münchen". ホスト名 münchen は、DNS ルックアップの前に Punycode に変換する必要があります: https://xn--mnchen-3ya.example/café?city=münchen. ただし、お待ちください。パスとクエリにも非 ASCII が含まれています。それらも変換してください: https://xn--mnchen-3ya.example/caf%C3%A9?city=m%C3%BCnchen. これで、ホスト名は Punycode になり、パスとクエリはパーセントでエンコードされます。ブラウザには、読みやすいように元の Unicode バージョンが表示されます。 HTTP リクエストにはエンコードされたバージョンが含まれます。

URL エンコーダおよびデコーダ ツールで、非 ASCII テキストを含むパスを貼り付け、単一値モード (パスのみ) とアドレス全体モード (完全な URL) を比較します。このツールは、パスのパーセントエンコードされた結果を表示します。ただし、ホスト名は別途 Punycode 変換する必要があります。ほとんどのエンコード ツールはこれをインラインで処理しないため、ツールのドキュメントを読んでください。

ホモグラフ攻撃とブラウザーが時々ピュニーコードを表示する理由 - 表示ルールの背後にあるセキュリティ上の理由

悪意のある攻撃者は、「https://xn--80akhbyknj4f.example" (punycode の「example.example」のキリル文字バージョン) など、見た目はラテン文字と同じに見えるキリル文字を使用してドメインを登録する可能性があります。ブラウザーがキリル文字としてデコードされて表示される場合、ユーザーは違いに気付かない可能性があります。同形異義語攻撃を防ぐために、ブラウザはピュニーコードのバージョンをデコードせずに表示することがあります。 「このドメインはすべてまたはほとんどが非 ASCII であるため、文字を認識できない可能性があります」という警告が表示されます。

URL エンコーダおよびデコーダは、エンコードおよびデコードのためのツールであり、セキュリティ評価のためのツールではありません。国際的なドメイン名を使用している場合は、punycode 表現がネットワークで認識されるものであることに注意してください。

これでカバーされないこと — Punycode アルゴリズムを手動で実行すること、または IDNA 2003 と 2008 の違い

IDNA は、時間の経過とともに複数のバージョンを経てきました。IDNA 2003 と IDNA 2008 は、特に正規化や仕様で許可されている Unicode 文字に関して、特定のエッジ ケースを異なる方法で処理します。一部の古いシステムは依然として IDNA 2003 を使用していますが、他のシステムはコンプライアンスの強化のために IDNA 2008 に移行しています。複数のバージョン間で互換性が必要なシステムを構築している場合、この違いは非常に重要です。システム要件を常に注意深く確認してください。

Punycode はブートストリング圧縮を使用します。実装は共通言語で行われますが、ホスト名システムで IDNA ポリシーを確認してください。解像度とディスプレイの動作を仮定するのではなくテストします。

要点: 2 つのジョブに対する 2 つのエンコーディング — URL エンコーダとデコーダがパーセント エンコードされた部分をどのように処理するか、およびパーセント エンコーダがホスト名に対して間違ったツールである理由

DNS は ASCII ラベルのみを理解する古いプロトコルであり、長さと文字に厳密な制限があるため、ホスト名には Punycode が必要です。パス、クエリ、フラグメントではパーセント エンコーディングが使用されます。これは、パーセント エンコーディングが Web 上で汎用的であり、これらの制約がないためです。これらは、2 つの完全に異なる問題に対する 2 つの別々のソリューションです。非 ASCII URL に遭遇すると、最初にホスト名が Punycode 変換され、次に残りがパーセント エンコーディングを使用します。

ほとんどの開発作業では、フレームワークまたはライブラリがこの変換をバックグラウンドで自動的に処理します。ただし、2 つの異なるエンコーディングが存在する理由を理解すると、国際 URL をデバッグするときや独自の URL 処理コードを正常に実装するときに混乱を避けることができます。