简体中文

开发者工具 · URL 编码器和解码器

在查询参数中编码重定向 URL,而不破坏它

· 工作原理

url 编码 查询参数 安全 oauth

编码为单个查询参数值的完整 URL,通过百分比编码保留结构
原始 ToolAcre 矢量图

将一个 URL 嵌套在另一个 URL 中是百分比编码最常见的错误地方。这篇文章展示了为什么必须对内部 URL 的 ?、& 和 = 进行编码、如何编码以及如何检查结果。

删除了一半参数的返回链接 — 内部 URL 被外部查询字符串吞没

删除一半参数的返回链接是每个开发人员都会遇到的调试模式。用户登录后,应用程序尝试重定向到 ?next=https://example.com/page?id=1&user=alice, 并且最终到达 example.com/page?id=1. 内部 URL 中的 & 符号被解析为外部查询参数之间的分隔符。两个具有不同分隔符的 URL 意味着必须对内部 URL 进行编码。

当将一个 URL 作为查询参数嵌套在另一个 URL 中时,该内部地址对于外层来说将成为不透明数据。问号、与号和等号不得作为结构分隔符被读取。百分比编码对它们进行转换: ?变为 %3F,& 变为 %26,= 变为 %3D。然后,外部解析器将编码后的字符串视为一个参数值。

两个 URL,两组分隔符 — 为什么内部 URL 只是外部 URL 的一个值

encodeURIComponent 会产生完全保护:encodeURIComponent("https://example.com/a?b=1&c=2") returns "https%3A%2F%2Fexample.com%2Fa%3Fb%3D1%26c%3D2"。每个结构字符都变成 %XX 表示法,因此外部解析器不能误解嵌套分隔符。像encodeURI这样的竞争方法会保留斜杠和问号不变,重新引入当该结果成为查询值时存在歧义。

服务器仅解码一次。提取下一个参数后,单个decodeURIComponent 调用会将内部URL 恢复为其原始形式。将结果解析为新的查询字符串,然后看到正确的参数结构。当同一个值经过多层时,双重解码是一种风险; %26 在一次解码后变为 &,并在第二次解码后保持 &。

对整个内部 URL 进行encodeURIComponent — 编码的内容包括:、/ 和?

基本规则很简单:任何在 URL 语法中有意义的字符,包括 : / ? = & #,出现在查询参数值中时必须采用百分比编码。这可确保外部解析器仅看到您想要的参数结构,而不会看到您传递的值中隐藏的任何意外分隔符。使用encodeURIComponent来完整可靠地处理这种编码。

在 URL 编码器和解码器中测试此编码:粘贴内部 URL,以值模式对其进行编码,观察 %XX 输出。使用解码器模式验证往返是否完全匹配。该工具演示了端到端编码,因此您可以放心地将结果直接复制到您的应用程序代码中。

工作示例:正确构建 ?next=https://example.com/a?b=1&c=2 — 编码字符串和服务器端解码

关键的安全边界与编码并存。服务器必须验证解码后的目标实际上可以安全地重定向到。百分比编码使 URL 结构明确;它不会使任意 URL 变得安全。当应用程序盲目遵循用户提供的 URL 时,就会出现开放重定向漏洞。验证需要明确的许可名单、域验证或用户确认。

编码修复了解析问题;验证修复了安全问题。这些是不同层面的单独关注点。 URL 编码器和解码器演示了正确的编码。服务器必须添加验证:对照列表进行检查、验证域或要求确认。如果没有验证,正确编码的重定向到任何域仍然可以被利用。

开放重定向风险 - 为什么服务器必须验证解码的目标,而不仅仅是解码它

常见错误累积于此。开发人员有时只对查询部分进行编码,而不修改斜杠,这会破坏结构。其他人对整个构造参数进行编码,包括 ?next=,从而创建双重编码。有些通过解析而不解码来检查有效性,误读编码结构。使用encodeURIComponent 进行构建可确保每种情况下的一致性和正确性。

另一个常见错误是相信浏览器会自动修复格式错误的参数。 URL 是数据,必须严格按照数据对待。 encodeURIComponent 是这项工作的标准工具。 URL 编码器和解码器将此过程保留在本地,以便您可以在交付生产之前验证确切的字节。

常见错误 - 仅对查询部分进行编码,或相信浏览器可以修复它

OAuth redirect_uri 参数完全遵循相同的模式。授权服务器将控制权传递给已知地址的客户端,通常是带有多个参数的完整 URL。将其编码为单个值可确保参数在传输中保存下来,并且客户端在使用前解码一次。 OAuth 流中的编码处理不当会导致令牌和回调参数在传输过程中消失。

OAuth 中的状态参数使用编码与加密签名相结合来实现 CSRF 保护。片段标识符保留在客户端,永远不会传输到服务器。无论编码如何,承载令牌都绝不能放置在重定向 URL 中,因为 URL 出现在日志、浏览器历史记录和引用标头中。

这不包括什么 - OAuth 状态参数和 CSRF 保护设计

测试策略:使用真实参数构造内部 URL,将其编码为外部值,在接收代码中对其进行解码。验证解码结果与原始结果逐字节相同。在生产部署之前使用 URL 编码器和解码器。检查网络流量和日志以确认正确到达并且编码数据没有被截断或损坏。

像 %2e 而不是 %2E 这样的拼写错误可能会正确解码,但在期望一致性的辅助系统中无法进行往返检查。不同平台上的库之间的编码不匹配很少见,但也是可能的;测试完整的往返行程可以在它们引起生产问题和客户投诉之前发现它们。

要点:将内部 URL 视为数据 — URL 编码器和解码器的单值模式如何对其进行完整编码及其解码器如何确认往返

编码边界很清晰:encodeURIComponent 将您的输入视为不透明数据,并转义除未保留的标点符号之外的每个字符,从而可以安全地嵌套在任何 URL 层中。验证边界是分开的:解码后,验证目的地是用户打算去的地方。使用 URL 编码器和解码器查看端到端的编码演示。

从一开始就将内部 URL 视为数据。将其编码为单个查询值,在收到时解码一次,然后在重定向之前应用验证。 URL 编码器和解码器将任何完整 URL 的百分比编码显示为单个查询值,并在本地验证往返。编码和验证都是必不可少的;该工具可以正确处理编码。