Punycode 如何服务国际化域名
DNS 历史上使用受限 ASCII 标签,而用户使用大量非 ASCII 文字。RFC 3492 的 Punycode 使用 Bootstring 算法把 Unicode 码点序列表示为字母、数字和连字符;国际化域名在负载前加 xn-- 形成 ASCII 兼容标签。
Punycode 每次处理一个标签,不处理点或完整 URL。本页提供单标签与完整域名模式。完整模式会把 U+3002、U+FF0E、U+FF61 规范化为 ASCII 点,保留可选根点,再逐标签编码或解码。
Punycode 不等于完整 IDNA。IDNA2008 与 UTS #46 还包含映射、规范化、上下文和脚本规则。为避免新增依赖,本实现采用 RFC 3492 加保守本地规则:只允许字母、标记、数字和连字符,ASCII 输出小写,标签不超过 63 字符,完整编码域名不超过 253 字符。
如何转换 Unicode 域名或标签
- 包含点分隔时选择完整域名,仅测试一个标签时选择单标签。
- 人类可读 Unicode 名称选择编码,已有 xn-- ASCII 名称选择解码。
- 只输入域名,不要包含协议、端口、路径、查询、邮箱本地部分。
- 根据错误修正空标签、非法字符、连字符位置、非规范 A-label 或长度。
- 生产注册和安全判断仍应使用维护中的完整 IDNA 库并遵循注册局策略。
Punycode 标签与完整域名示例
示例展示 RFC 3492 负载、xn-- 前缀、逐标签处理、大小写规范化和 Unicode 句点变体。
| 输入 | 输出 | 转换方向 | 说明 |
|---|---|---|---|
bücher |
xn--bcher-kva |
编码 | 德语标签. 基础 ASCII 字母保留可读,非 ASCII 的 ü 编码到后缀。 |
mañana |
xn--maana-pta |
编码 | 西班牙语标签. 原始 RFC 3492 负载是 maana-pta,DNS A-label 再加 xn--。 |
例子 |
xn--fsqu00a |
编码 | 中文标签. 没有基础 ASCII 字符时,负载全部由算法编码。 |
Münich.Example |
xn--mnich-kva.example |
编码 | 完整域名. 每个标签独立处理,ASCII 输出统一小写。 |
例子。测试 |
xn--fsqu00a.xn--0zwm56d |
编码 | Unicode 句点. 表意文字句号会先规范化为 ASCII 点。 |
XN--BCHER-KVA.example |
bücher.example |
解码 | 解码 A-label. DNS ASCII 匹配不区分大小写,输出采用规范小写。 |
标签语法、大小写、句点与校验
ASCII 标签统一小写,只允许字母、数字和连字符,不能以连字符开头或结尾,最长 63 字符。xn-- 标签会解码再重编码以检查规范性。
Unicode 标签在本实现中只允许 Unicode 字母、组合标记、数字和内部连字符。空格、下划线、斜杠、冒号、@、emoji 与标点被拒绝。
- 完整模式接受 ASCII 点和三种常见 Unicode 句点。
- a..b 这样的空内部标签非法,只保留一个可选末尾根点。
- https:// 与 /path 不属于域名标签。
- 编码标签最长 63 个 ASCII 字符,完整域名最长 253。
- A-label 输出小写,便于规范展示。
RFC 3492 Bootstring 算法概览
编码器先复制基础 ASCII 码点;存在基础字符时用连字符分隔后缀。随后维护当前码点 n、delta 和自适应 bias,反复寻找最小未处理码点,并以 36 进制广义变长整数输出差值。
偏置自适应让相近码点更紧凑。数字 0-25 映射 a-z,26-35 映射 0-9。解码器恢复 n 和插入位置,把码点插回序列而不是简单追加。
实现会防止 JavaScript 安全整数溢出,拒绝超出 U+10FFFF 和代理区的值,按保守规则验证,并通过重编码检查 xn-- 规范形式。它不会执行 DNS 查询。
Punycode 的实际用途
Punycode 主要是互操作与检查层。用户通常看到经过安全策略处理的 Unicode,协议、证书和日志可能显示 A-label。
| 项目 | 说明 |
|---|---|
| 读取 DNS 与证书数据 | 把日志、zone 文件或 TLS 证书中的 xn-- 标签转换为可读形式。 |
| 准备国际化标签 | 查看 IDNA 应用可能使用的 ASCII 兼容表示,同时注意注册局可增加限制。 |
| 调试邮箱域名 | 国际化地址的域名部分可能使用 A-label,本地部分则遵循其他规则。 |
| 检查显示不一致 | 在重定向、Cookie、证书和允许列表问题中比较 Unicode 与 ASCII 精确形式。 |
| 测试 RFC 3492 实现 | bücher、mañana、例子是验证编码与插入顺序的常用向量。 |
Punycode 错误与 IDN 安全限制
可成功转换不代表安全。Unicode 中存在与拉丁字母相似的字符、组合序列和混合脚本,防同形攻击需要浏览器显示策略、注册局规则和业务安全控制。
浏览器可能先执行 UTS #46 映射与规范化。本工具明确采用较窄、无依赖的配置,不冒充所有浏览器和注册局行为。
- 下划线常见于某些服务记录,但不是本页主机名标签。
- emoji 与符号标签被保守规则拒绝。
- 空 xn-- 负载非法。
- 解码后无法重编码为同一小写 A-label 时拒绝。
- 成功转换也不表示域名存在、可注册或可信。
Punycode、IDNA 与 URL 编码
Punycode 是 Unicode 码点编码算法;IDNA 是决定域名标签映射与有效性的更大框架;UTS #46 是很多应用采用的兼容处理规范。
URL 百分号编码处理 URL 组件字节,不会把 Unicode 主机名变成 DNS A-label。完整 URL 解析器会分别处理主机与路径/查询。
| 项目 | 说明 |
|---|---|
| IDNA2008 | 定义国际化标签有效性和上下文规则,范围大于 Punycode 算法。 |
| UTS #46 | 提供兼容映射,本工具不声称完整实现。 |
| URL 编码 | 百分号编码 URL 组件,不替代主机名的 Punycode/IDNA。 |