写 Firefox 扩展的人都在等这个:publicSuffix.isKnownSuffix() 今天终于把 invalid hostname 当 error 而不是 false 了
写过 Firefox 扩展的人都踩过这个坑——调用 browser.publicSuffix.isKnownSuffix() 检查一个 hostname 是否为公共后缀,以前传进去一个非法 hostname,它只会默默返回 false。今天 Firefox 158 把这件事彻底改了:invalid hostname 直接抛异常,而不是静默返回 false。
这个坑是怎么来的
publicSuffix.isKnownSuffix() 的原始设计很简单:
// 以前:非法 hostname 只返回 false,扩展照常运行
browser.publicSuffix.isKnownSuffix("not-a-valid-host%")
.then(result => console.log(result)) // false
.catch(err => console.error(err)); // 从不进入这里
问题在于它”太宽容”了。 Mozilla 安全工程师 Rob Wu 在 Bug 2059819 中指出:Firefox 的实现底层用了 getKnownPublicSuffixFromHost 和 convertUTF8toACE,这两个方法允许了 %、#、/、?、@、[、]、^、| 这些根本不属于 domain 名字符。
换句话说,以下这些根本不是合法 hostname 的字符串,在修复前全部返回 false 而不报错:
// 修复前:全部返回 false,不报任何错误
browser.publicSuffix.isKnownSuffix("example.com#") // false
browser.publicSuffix.isKnownSuffix("foo/bar.com") // false
browser.publicSuffix.isKnownSuffix("example.com?query") // false
browser.publicSuffix.isKnownSuffix("test@[::1]") // false
最严重的是:*.ck 这类通配符公共后缀,原本应该只匹配真正的公共域名,但 bug 让它能匹配任何包含这些非法字符的字符串——这是一个安全漏洞。
修复后:从 false 变成抛异常
Firefox bug 2066620 在 Firefox 155 修好,随 Firefox 158 稳定版正式发布:
// 修复后:invalid hostname 直接抛异常
browser.publicSuffix.isKnownSuffix("not-a-valid-host%")
.then(result => console.log(result))
.catch(err => console.error(err)); // TypeError: Invalid hostname
Mozilla 工程师 Rob Wu 在 Phabricator review 中描述了修复逻辑:在调用 getKnownPublicSuffixFromHost 之前,先用 ensureValidHostname() 做一次输入校验——IPv6 地址会抛异常,但合法 IPv4 和域名不会受影响。
实际上影响哪些扩展
这个行为变更不会影响正常用法:
// 正常用法:始终返回正确结果,不受影响
browser.publicSuffix.isKnownSuffix("github.io") // true
browser.publicSuffix.isKnownSuffix("example.com") // false
browser.publicSuffix.isKnownSuffix("user.github.io") // false
受影响的是那些没有做输入校验的扩展,例如:
// ❌ 有问题的写法:直接用 URL parsing 结果调用 API
const url = new URL(inputString);
const hostname = url.hostname;
// 如果 inputString 本身非法,hostname 可能不合法
// ❌ 有问题的写法:只判断非 null
if (hostname) {
const isPublic = await browser.publicSuffix.isKnownSuffix(hostname);
}
这类代码在修复前会默默得到 false(因为非法输入被宽容处理),修复后直接抛异常,导致扩展功能中断。
Chrome 对比
Chrome 从 Chrome 153 开始支持标准化的 browser.publicSuffix API,与 Firefox 保持相同的语义。扩展开发者在跨浏览器写代码时需要明确:这不是一个”查询成功与否”的布尔 API,而是一个”输入合法性 + 查询”的 API。
迁移三步走
第一步:更新输入校验
// ✅ 推荐:先校验合法性,再查 PSL
function isValidHostname(hostname) {
if (!hostname || typeof hostname !== "string") return false;
return /^[a-zA-Z0-9.-]+$/.test(hostname) && hostname.length <= 253;
}
if (isValidHostname(rawInput)) {
const result = await browser.publicSuffix.isKnownSuffix(rawInput);
} else {
console.warn("Invalid hostname:", rawInput);
}
第二步:加上 try/catch
// ✅ 推荐:try/catch 兜底
try {
const result = await browser.publicSuffix.isKnownSuffix(rawInput);
return result;
} catch (err) {
console.error("PSL query failed:", err);
return false; // 保守降级
}
第三步:测试边界情况
// 边界 hostname 测试用例
[
"github.io", // true
"user.github.io", // false
"example.com#", // invalid → 抛异常
"foo/bar.com", // invalid → 抛异常
"192.168.1.1", // false (不是公共后缀)
"localhost", // false
"*.ck", // true (通配符公共后缀)
].forEach(async (hostname) => {
console.log(hostname, await browser.publicSuffix.isKnownSuffix(hostname));
});
结论
publicSuffix.isKnownSuffix() 这次改的不是功能,而是错误处理语义:从”非法输入静默返回 false”变成”非法输入抛异常”。这是一个正确的安全修复,但对没有做输入校验的扩展来说是破坏性变更。Firefox 158 将在 2026 年 10 月 13 日发布稳定版,扩展作者现在有约一周时间做兼容处理。
评论区
登录后可评论。