为什么要对 %2B 字符串进行 urldecode?

Yel*_*fog 6 html email url urldecode

[这可能不完全是一个编程问题,但它是一个最好由程序员回答的难题。我首先在 Pro Webmasters 网站上尝试过,以压倒性的沉默]

我们的网站上有电子邮件地址验证流程。该站点首先生成一个适当的密钥作为字符串

mykey
Run Code Online (Sandbox Code Playgroud)

然后将该密钥编码为一堆字节

&$dac~?????!
Run Code Online (Sandbox Code Playgroud)

然后 base64 编码那串字节

JiRkYWN+yoyIhIQ==
Run Code Online (Sandbox Code Playgroud)

由于此键将作为要放置在 HTML 电子邮件中的 URL 的查询字符串值给出,因此我们需要先对其进行 URLEncode,然后对结果进行 HTMLEncode,从而为我们提供(示例中 HTMLEncoding 没有效果,但是我懒得重新编写示例)

JiRkYWN%2ByoyIhIQ%3D%3D
Run Code Online (Sandbox Code Playgroud)

然后将其嵌入作为电子邮件的一部分发送的 HTML 中,例如:

click <a href="http://myapp/verify?key=JiRkYWN%2ByoyIhIQ%3D%3D">here</a>. 
Or paste <b>http://myapp/verify?key=JiRkYWN%2ByoyIhIQ%3D%3D</b> into your browser.
Run Code Online (Sandbox Code Playgroud)

当接收用户单击链接时,站点会收到请求,提取查询字符串“key”参数的值,base64 对其进行解码、解密,并根据站点逻辑执行相应的操作。

然而,有时我们会有用户报告他们的点击无效。一位这样的用户向我们转发了他发送的电子邮件,经过检查,HTML 已被转换为(根据上面的示例进行说明)

click <a href="http://myapp/verify?key=JiRkYWN+yoyIhIQ%3D%3D">here</a>
Or paste <b>http://myapp/verify?key=JiRkYWN+yoyIhIQ%3D%3D</b> into your browser.
Run Code Online (Sandbox Code Playgroud)

也就是说,%2B 字符串 - 但没有其他百分比编码的字符串 - 已转换为加号。(这肯定给我们留下了正确的值——我已经查看了相应的 SMTP 日志)。

key=JiRkYWN%2ByoyIhIQ%3D%3D
key=JiRkYWN+yoyIhIQ%3D%3D
Run Code Online (Sandbox Code Playgroud)

所以我认为有两种可能性:

  1. 我正在做一些愚蠢的事情,我看不到,或者

  2. 一些邮件客户端将 %2b 字符串转换为加号,也许是为了应对人们误将 URLEncoding 加号的问题

在 1 的情况下 - 它是什么?在 2 的情况下 - 是否有一种标准的、已知的方法来处理这种情况?

非常感谢您的帮助

Vor*_*ung 1

问题就出在这一步

经检查,HTML 已转换为(用上面的示例表示)

click <a href="http://myapp/verify?key=JiRkYWN+yoyIhIQ%3D%3D">here</a>
Or paste <b>http://myapp/verify?key=JiRkYWN+yoyIhIQ%3D%3D</b> into
your browser.
Run Code Online (Sandbox Code Playgroud)

也就是说,%2B 字符串 - 但没有其他百分比编码字符串 - 已转换为加号

您在“另一端”的应用程序一定缺少转义步骤。无论是否有 %2B 还是 + 像 perls uri_unescape 这样的函数都会返回一致的答案

DB<9> use URI::Escape;
DB<10> x uri_unescape("JiRkYWN+yoyIhIQ%3D%3D")
0  'JiRkYWN+yoyIhIQ=='
DB<11> x uri_unescape("JiRkYWN%2ByoyIhIQ%3D%3D")
0  'JiRkYWN+yoyIhIQ=='
Run Code Online (Sandbox Code Playgroud)

这是应该发生的事情。我所展示的只是步骤。我在调试器中使用 perl。步骤54将字符串编码为base64。步骤55展示了如何将base64编码的字符串制作成uri转义参数。步骤56和57是客户端应该执行的解码操作。

一种可能的解决方法是确保您的 base64“密钥”不包含任何加号!

  DB<53> $key="AB~"
  DB<54> x encode_base64($key)
0  'QUJ+
'
  DB<55> x uri_escape('QUJ+') 
0  'QUJ%2B'
  DB<56> x uri_unescape('QUJ%2B')
0  'QUJ+'
  DB<57> $result=decode_base64('QUJ+')
  DB<58> x $result
0  'AB~'
Run Code Online (Sandbox Code Playgroud)