Punycode

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

什么是Punycode?

Punycode是在RFC 3492中定义的编码语法,它将Unicode字符串转换为DNS支持的有限ASCII字符集。它是使国际化域名(IDN)可能的技术基础,允许任何语言的域名与现有DNS基础设施配合工作。

Punycode解决的问题

域名系统是在1980年代设计的,只考虑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:

用户输入:中文.com

浏览器发送:xn--fiq228c.com(到DNS)

浏览器显示:中文.com(在地址栏中)

开发者实现

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

// 编码为Punycode

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

// 结果:xn--mnchen-3ya.de

// 从Punycode解码

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

// 结果:münchen.de

Python
domain = 'münchen.de'

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

# 结果:xn--mnchen-3ya.de

URL处理

在处理包含IDN的URL时:

// URL API自动处理Punycode

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(西里尔'а'和'р')

apple.com(拉丁字母)

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

浏览器保护

为了对抗欺骗,浏览器实现了保护:

1. 混合脚本检测:为可疑的IDN显示Punycode而不是Unicode

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

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

在API中使用Punycode

在构建域名工具时:

始终存储Punycode:在内部使用ASCII形式保持一致性和数据库索引。 接受两种形式:让用户输入Unicode或Punycode,根据需要转换。 显示Unicode:在用户界面中显示人类可读的形式。
function normalizeDomain(input) {

const punycode = require('punycode/');

// 转换为小写Punycode以供内部使用

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

}

Punycode对大多数用户是透明的,但对构建国际化网络应用的开发者至关重要。

将知识付诸实践

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