News Hacker|极客洞察

27 74 天前 lemire.me
🤦URL 中的换行:浏览器容错但规范与安全不支持
把换行放进链接并上线,这就是明智之举?

🎯 讨论背景

讨论源自一篇声称“可以在 URL 中使用换行字符”的博文,评论者追溯到 Wikipedia 的 Base64 与 data URI 条目并发现规范层面 data URI 不允许空白字符(data URI scheme 用于在 URL 中嵌入数据,通常配合 Base64 使用)。与此同时,HTML 4/5 的属性解析在属性值内部会忽略或移除换行,这使得浏览器实现看起来“容忍”但并不等同于规范允许。评论还强调实际风险:HTTP 使用 CRLF 作为头分隔符,任意换行可能导致头注入或解析错误;链路上的基础设施(比如 CDN,即内容分发网络)也可能拦截或过滤异常请求。总体讨论在“浏览器容错 vs 规范禁止”以及“可行性不等于可部署或安全”之间展开。

📌 讨论焦点

HTML 属性解析会移除换行(标题误导)

多条评论认为原帖标题容易误导:实际情况不是浏览器把换行当作 URL 的一部分,而是在 HTML 属性(例如 HREF)内解析时会移除 ASCII 制表符或换行,从而不改变链接目标。有人补充浏览器可能会先抛出校验错误、删除违规字符然后重试并成功,体现为实现层的容错而非规范允许。因此更准确的描述应强调“浏览器会移除属性内的换行”,而不是宣称换行在 URL 中有效。

[来源1] [来源2] [来源3]

规范 vs 实现:data URI 与 Base64 的空白限制

有评论引用 Wikipedia 上的 Base64 和 data URI 条目指出,规范中明文写着 data URI 不允许出现 whitespace(空白字符)。同一评论又指出 HTML 4/5 在属性值内部会忽略 linefeeds(换行),这制造了规范层面与浏览器实现之间的差异。结论是:在 HTML 属性上下文里可能被“容忍”或被解析器修正,但在其它上下文(如纯 data URI 使用或其他协议解析)空白并不会被忽略并仍然不合规范。

[来源1]

安全与基础设施限制(HTTP 头与 CDN)

评论提醒换行在 HTTP 中作为头部分隔符(CRLF),在请求或 URL 中插入换行会导致头注入或请求解析错误,这构成明显的安全风险。也有人指出许多 CDN(内容分发网络,CDN)例如 Cloudflare 会过滤或阻断非标准 HTTP 动词或异常请求,意味着传输链路或代理可能拒绝或修改这些请求。综合观点认为即便浏览器端容错,上游基础设施更可能触发失败或安全问题,因此不能在生产环境依赖该行为。

[来源1] [来源2]

实践经验与编码建议:别这么做(正则、文件名、不可见字符)

多位评论通过比喻和经验提醒“能做不等于该做”:有人用把 pickle 汁倒进麦片来形象说明不应把不可见字符放入常用数据流。编写正则或输入校验时必须考虑换行、制表符等不可见控制字符,否则检测会失效或误判;文件系统与工具对 vertical tabs、空格等字符处理不一,实际兼容性问题不少。总体建议是避免在 URL、文件名或公共接口中依赖这些边缘字符,以免增加故障与维护成本。

[来源1] [来源2] [来源3] [来源4] [来源5]

📚 术语解释

data URI scheme(data:): 一种把数据直接内联到 URL 的机制(例如 data:...),常用于在页面中嵌入小文件或图像的 base64 编码内容。规范通常不允许在 data URI 本体中出现未编码的空白字符。

Base64: 一种把二进制数据编码为 ASCII 可打印字符的常用方法,常用于 data URI 的 payload 编码。Base64 输出应由固定字符集组成,不应包含未经编码的空白或换行。

HREF attribute(HTML 属性): HTML 元素(如 )的 href 属性用于指定链接目标。HTML 解析器在某些情况下(HTML 4/5 的行为)会在属性值内部忽略或移除换行与制表符,表现为浏览器端的容错。

CRLF / HTTP 头分隔符: CRLF(回车+换行)是 HTTP 协议用来结束头部行并分隔头部与正文的标志。未正确处理的换行可能导致头注入(header injection)或头分割(header splitting)等安全与解析问题。