在HTTP URL的路径部分,斜杠(“/”)和编码后的斜杠(“%2F”)是否等价?

106

我有一个网站,会根据URL路径(而不是查询字符串)中的/%2F进行不同处理。在RFC或现实世界中,这样做是不是不好的事情?

我之所以问,是因为我一直在使用的web框架(Ruby on Rails)以及底层的组件(Passenger,Apache等)给我带来了一些小惊喜(例如,我必须启用ALLOW_ENCODED_SLASHES才能让Apache正常工作)。现在我倾向于完全摒弃编码斜杠,但我想知道是否应该在遇到涉及编码斜杠的奇怪行为时提交错误报告。

至于为什么我最初要使用编码斜杠,基本上是因为我有这样的路由:

:controller/:foo/:bar

这里的:foo是类似于可能包含斜杠的路径。我认为最直接的方法是URL转义foo,这样斜杠就会被路由机制忽略。但现在我有疑虑了,很明显这些框架并不真正支持这样做,但根据RFC来说,这样做是错的吗?

下面是一些我收集到的信息:

RFC 1738 (URLs):

通常情况下,当一个八位字节被表示成字符时,它的解释也是相同的,当它被编码时也是如此。然而,对于保留字符来说,这个规则是不适用的:编码一个为特定协议保留的字符可能会改变URL的语义。

RFC 2396 (URIs):

这些字符被称为“保留字符”,因为它们在URI组件中的使用仅限于其保留目的。如果URI组件的数据与保留目的冲突,则必须在形成URI之前对冲突的数据进行转义。

(这里的转义是否意味着除了编码保留字符之外的其他操作?)

RFC 2616 (HTTP/1.1):

除了“保留”和“不安全”字符集(请参见RFC 2396 [42])中的字符外,其他字符等同于它们的“%HEX HEX”编码。

对于Rails,这里还有一个bug报告,他们似乎期望编码后的斜杠行为不同:

没错,我预计会得到不同的结果,因为他们指向不同的资源。

它正在根目录下查找文字文件foo/bar。未转义版本正在查找目录foo中的文件bar

从RFC来看,原始与编码是相当于非保留字符,但保留字符的情况如何呢?


相关链接:https://dev59.com/RG3Xa4cB1Zd3GeqPkOoI - unor
PHP用户使用前置控制器时:$_GET和$_REQUEST已经被URL解码,这可能会导致斜杠问题,因为您将无法确定哪个是反斜杠,哪个是%2F。如果您绝对需要查看发送的请求,请查看$_SERVER['REQUEST_URI']。另请参见urldecode()@php.net - Patrick James McDougle
7个回答

45

从你收集的数据来看,我倾向于认为URI中编码的/应该在应用程序或CGI级别再次被视为/

也就是说,如果您使用Apache和mod_rewrite等工具,则不会针对包含编码斜杠的URI匹配预期斜杠的模式。 然而,一旦调用适当的module/cgi/...来处理请求,就由它来解码,例如检索包括作为URI第一组件的斜杠的参数。

如果您的应用程序随后使用这些数据来检索文件(其文件名包含斜杠),那可能是个问题。

总之,我认为在/%2F的行为上存在差异很正常,因为它们的解释将在不同的层次上进行。


2
这正是我一直在思考的问题。不幸的是,在现实世界中似乎没有太多支持以这种方式进行操作的方法。目前我会继续尝试其他解决方案,但如果我从头开始,我会尝试另一种转义机制。 - user85509
@user85509 我在想,当我看到编码斜杠的奇怪行为时,是否应该提交错误报告。 - 每次观察到与RFC不符的行为时,请提交错误报告,RFC明确指出“/”作为保留字符与其百分比编码形式“%2F”不同。 - Piotr Dobrogost

34

1
查询怎么办?比如,查询没有分层结构。它们只是变量。很遗憾W3C的推荐并没有对此进行解释。 - Eksapsy

11

我也有一个网站,其中许多URL带有URL编码字符。 我发现许多Web API(包括Google网站管理员工具和几个Drupal模块)会因为URL编码的字符而出现问题。 许多API在其过程中自动解码URL,然后将结果用作URL或HTML。 当我发现这些问题之一时,通常会对该API的结果进行双重编码(这将%2f转换为%252f)。 但是,这将破坏其他不希望双重编码的API,因此这不是普遍适用的解决方案。

就我个人而言,我正在尽可能地消除我的URL中的特殊字符。

此外,我在我的URL中使用ID号码,它们不依赖于URL解码:

example.com/blog/my-amazing-blog%2fstory/yesterday

变成了:

example.com/blog/12354/my-amazing-blog%2fstory/yesterday

在这种情况下,我的代码仅使用12354来查找文章,而URL的其余部分则被我的系统忽略(但仍用于SEO)。 此外,此数字应出现在未使用的URL组件之前。这样,即使%2f被错误解码,URL仍将起作用。

此外,请务必使用规范标记以确保URL错误不会转化为重复内容。


这种方法似乎非常适用于reddit.com。 - StockB

4

3
如果:foo在其自然形式中包含斜杠,该怎么办?您不希望它这样。这难道不是建议试图保留的区别吗?它特别指出

与Unix和其他磁盘操作系统文件名约定的相似性应被视为纯属巧合,并且不应被视为URIs应被解释为文件名。

如果要构建一个在线接口来备份程序,并希望将路径表示为URL路径的一部分,则对文件路径中的斜杠进行编码是有意义的,因为那不是资源层次结构的一部分 - 更重要的是,路由。 /backups/2016-07-28content//home/dan/ 在双斜杠中失去了文件系统的根目录。转义斜杠是我阅读时正确的区分方式。

-1

请尝试以下代码:obj=here,您可以使用任何对象...

Gson gson = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
       return Base64.getUrlEncoder().withoutPadding().encodeToString(gson.toJson(obj).getBytes());

这个问题似乎与Java无关。他们说他们正在使用CGI。 - Stephen Ostermiller
1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

-4

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接