Punycode 转换(国际化域名)

将包含日语等非 ASCII 字符的国际化域名(IDN)与 Punycode(ASCII 兼容编码)相互转换。

Punycode 是什么

DNS 在历史上只能处理 ASCII 字符。然而人们希望使用像「日本語.jp」这样**含有汉字与假名的域名**,为此搭起桥梁的便是 Punycode(RFC 3492)。它把 Unicode 字符串可逆地转换为以 `xn--` 开头的 ASCII 字符串,从而在不改动既有 DNS 的前提下实现国际化域名(IDN)。

转换结果对人而言不可读,这正是设计使然:`日本語.jp` 会变成 `xn--wgv71a119e.jp`。**浏览器的地址栏会隐去转换后的样貌,改以原本的文字显示**,因此平时并不会意识到它的存在。但这种外观上的落差**也是可被钓鱼攻击利用的弱点**——用西里尔字母「а」冒充拉丁字母「a」之类难以分辨的字符来伪造域名,已经造成过实际的麻烦。本工具可进行双向转换,**所有处理都在浏览器内完成。**

转换的步骤

  1. 选择转换的方向 在「域名→Punycode」与「Punycode→域名」之间择一。
  2. 输入域名 请连同顶级域一并输入,如 `日本語.jp`。
  3. 查看结果 会显示以 `xn--` 开头的转换结果,或还原后的原始文字。
  4. 对照确认 借由转换后的 ASCII 表示,可确认**是否混入了容易混淆的字符**。

用好本工具的小技巧

  • 由多个标签(以 `.` 分隔的部分)组成的域名也会按标签自动判断并转换:仅含 ASCII 字符的标签保持不变,只有包含非 ASCII 字符的标签才会转换为带 `xn--` 前缀的形式。
  • 在"Punycode → 域名"模式下,只有包含 `xn--` 前缀的标签会被解码,其余标签将原样保留。
  • 该转换逻辑不仅适用于域名,也可应用于邮箱地址中 `@` 之后的部分(域名部分)。
  • 在浏览器地址栏中实际输入国际化域名时,大多数浏览器会在内部先转换为 Punycode,然后再进行 DNS 解析。

这些场景会用到

注册或设定中文、日文域名

DNS 区域文件与服务器证书有时需要 Punycode 表示。

确认邮件的发件人

**显示名看似正规,换算成 Punycode 后却是另一个域名**——这样的案例确实存在。

解读日志中出现的 xn--

可查出访问日志或报表中出现的 `xn--` 字符串究竟指向何处。

检验设定文件

可用于确认 nginx 或 Apache 的设定中能否直接书写国际化域名。

Punycode 的术语

Punycode
把 Unicode 字符串可逆地转换为 ASCII 字符串的方式(RFC 3492)。**转换结果必定以 `xn--` 开头。**
IDN(国际化域名)
含有非 ASCII 字符的域名。在内部会被转换为 Punycode 以通过 DNS。
xn--
标示该标签经 Punycode 编码的前缀,称为 ACE 前缀。
标签
域名以点分隔的各个部分。**转换是逐个标签进行的。**
同形异义字攻击
以外观极为相似的其他字符伪造域名的手法。**换算成 Punycode 表示便可识破。**
IDNA
为在 DNS 中处理 IDN 而制定的一系列规范,现行为 IDNA2008(RFC 5890 之后)。

常见问题

Punycode(RFC 3492)是一种编码方式,用于将包含日语、中文、阿拉伯语等 Unicode 字符的域名(即国际化域名,IDN)转换为 DNS 能够处理的纯 ASCII 字符串。转换后的标签会带有 `xn--` 前缀。

DNS(域名系统)最初的设计只考虑了 ASCII 字符,因此包含日语字符或表情符号的域名无法直接被解析。Punycode 通过将含非 ASCII 字符的域名转换为 ASCII 字符串,使得在完全不改变现有 DNS 基础设施的前提下实现国际化域名成为可能。

`xn--` 被称为"ACE 前缀"(ASCII Compatible Encoding prefix,ASCII 兼容编码前缀),用于向 DNS 及相关软件表明该标签是经 Punycode 编码的国际化域名。浏览器等软件识别到该前缀后,通常会将其解码为原始的 Unicode 字符串显示给用户。

是的,这是一种被称为"IDN 同形字攻击"的钓鱼手段。已有报告指出,攻击者利用外观几乎相同但实际不同的字符(例如西里尔字母的"а"与拉丁字母的"a")编码生成 Punycode 域名(例如 `xn--80ak6aa92e.com`),冒充正规域名。主流浏览器的应对措施包括:当检测到可疑的字符混用时,在地址栏中保持显示 Punycode 形式(以 `xn--` 开头的字符串),而不显示解码后的内容。
工具君

闲话 ― "猫"与"日本語"如何变成域名的幕后故事

国际化域名(IDN)的讨论始于上世纪 90 年代后期,但标准化经历了很长时间。为了在不改变 DNS 核心结构的前提下处理非 ASCII 字符,业界曾提出多种方案,最终采用了"在应用层(客户端)完成编码与解码,DNS 服务器本身保持不变"的 Punycode 方案,并于 2003 年正式标准化为 RFC 3492。

"Punycode"这个名字据说源自"Unicode"与"an amusing pun"(有趣的双关语)的结合,其算法本身是将更通用的 Bootstring 编码方法(由 IBM 研究人员设计,用于将任意字符集编码为受限字符集的通用方法)针对域名场景加以特化而成。就连"Punycode"这个名字的由来本身也带有几分玩笑意味,颇能体现开发者社区特有的幽默感。

如今,日语域名(`.jp`)以及表情符号域名(例如确实存在的 `💩.la`)等使用各种语言和符号的域名已被实际注册和使用,但在这些域名背后,始终都要经过 Punycode 的转换处理。即便是浏览器地址栏中显示的优美的日语域名,在与 DNS 服务器通信时,实际传输的也是以 `xn--` 开头的朴素 ASCII 字符串。