Punycode

域名基础
一种编码系统,将Unicode域名转换为ASCII兼容格式,使国际化域名能够与DNS配合使用。
← 返回词汇表

什么是 Punycode?

Punycode 是 RFC 3492 定义的一种编码语法,用于将 Unicode 字符串转换为 DNS 支持的有限 ASCII 字符集。它是国际化域名(IDN)的技术基础,让任何语言的域名都能使用现有 DNS 基础设施。

Punycode 解决的问题

域名系统在 20 世纪 80 年代设计时只考虑了 ASCII 字符。DNS 标签只能包含:

这一限制排除了数十亿主要不使用拉丁字母的互联网用户。Punycode 通过把任意 Unicode 字符串编码为有效 ASCII,弥合了这一差距。

Punycode 编码如何工作

Punycode 使用一种巧妙的算法,在保留 ASCII 字符的同时,将非 ASCII 字符编码为紧凑的 ASCII 表示形式。

编码过程

1. 分离字符:将 ASCII 字符与非 ASCII 字符分开

2. 复制 ASCII:保留所有 ASCII 字符原本的位置

3. 编码非 ASCII:使用通用的可变长度整数编码

4. 添加前缀:添加 “xn--” 以表示 Punycode 编码

示例

原始(Unicode)编码(Punycode)
münchenxn--mnchen-3ya
北京xn--fiqs8s
münchen.dexn--mnchen-3ya.de
中文.comxn--fiq228c.com
café.comxn--caf-dma.com

“xn--”前缀

“xn--”前缀称为 ACE(ASCII 兼容编码)前缀。它向 DNS 解析器和应用程序表明,该标签包含经过 Punycode 编码的内容。这个前缀:

实际使用 Punycode

浏览器处理

现代浏览器会自动处理 Punycode:

User types: 中文.com

Browser sends: xn--fiq228c.com (to DNS)

Browser displays: 中文.com (in address bar)

开发者实现

JavaScript(Node.js)
const punycode = require('punycode/');

// Encode to Punycode

const encoded = punycode.toASCII('münchen.de');

// Result: xn--mnchen-3ya.de

// Decode from Punycode

const decoded = punycode.toUnicode('xn--mnchen-3ya.de');

// Result: münchen.de

Python
domain = 'münchen.de'

encoded = domain.encode('idna').decode('ascii')

# Result: xn--mnchen-3ya.de

URL 处理

处理包含 IDN 的 URL 时:

// URL API handles Punycode automatically

const url = new URL('https://中文.com/path');

console.log(url.hostname); // xn--fiq228c.com

console.log(url.href); // https://xn--fiq228c.com/path

安全影响

Punycode 可以表示任意 Unicode 字符,因此会带来安全风险:

视觉欺骗

攻击者可以注册外观与合法网站相同的域名:

аррlе.com (Cyrillic 'а' and 'р')

apple.com (Latin letters)

在某些字体中,两者显示相同,但实际是不同的域名。

浏览器保护

为防止欺骗,浏览器会实施以下保护:

1. 混合文字检测:对可疑的混合文字域名显示 Punycode

2. 易混淆字符检测:标记使用外观类似 ASCII 字符的域名

3. 白名单:仅对知名 TLD 允许显示 Unicode

在 API 中使用 Punycode

构建域名工具时:

始终存储 Punycode:在内部使用 ASCII 形式,以保持一致性并便于数据库索引。 接受两种形式:允许用户输入 Unicode 或 Punycode,并按需转换。 显示 Unicode:在用户界面中显示便于阅读的形式。
function normalizeDomain(input) {

const punycode = require('punycode/');

// Convert to lowercase Punycode for internal use

return punycode.toASCII(input.toLowerCase());

}

Punycode 对大多数用户是透明的,但对于构建国际化 Web 应用的开发者却是必备知识。

将知识付诸实践

使用 DomScan 的 API 检查域名可用性、健康状态等。