【问题标题】:Java Reading Undecoded URL from ServletJava 从 Servlet 读取未解码的 URL
【发布时间】:2010-11-01 06:03:21
【问题描述】:

假设我有像 '=&?/;#+%' 这样的字符串作为我的 URL 的一部分,让我们这样说:

example.com/servletPath/someOtherPath/myString/something.html?a=b&c=d#asdf

其中 myString 是上面的字符串。我已经对关键部分进行了编码,所以 URL 看起来像

example.com/servletPath/someOtherPath/%3D%26%3F%2F%3B%23%2B%25/something.html?a=b&c=d#asdf

到目前为止一切顺利。

当我在 servlet 中读取 request.getRequestURI()request.getRequestURL()request.getPathInfo() 中的任何一个时,返回的值已经被解码,所以我很喜欢

someOtherPath/=&?/;#+%/something.html?a=b&c=d#asdf

我无法区分真正的特殊字符和编码字符。

我通过完全禁止上述字符解决了特定问题,这在这种情况下有效,但我仍然想知道有没有办法在 servlet 类中获取未解码的 URL。

另一个编辑:当我昨晚遇到这个问题时,我太累了,没有注意到真正发生了什么,这更奇怪!我已经映射了 servlet,比如说 /servletPath /* 之后我可以根据路径的其余部分放置我想要的任何内容并让我的 servlet 响应,except 当路径中有 %2F 时。在那种情况下,请求永远不会命中 servlet,我得到 404!如果我输入 '/' 而不是 %2F 它可以正常工作。我在 Linux 上的 Java 1.6.0-04 上运行 Tomcat 6.0.14。

【问题讨论】:

  • 如果字符串已经被解码,为什么它会有一个 %2f 呢?
  • 返回的值是什么样的,你希望它是什么?它是否相关?我真的不知道问题出在哪里。
  • 听起来像是试图解码非法和格式错误的 URL。像这样在规范之外运行可能会导致一系列问题。您可以控制更改数据传递的方式吗?例如转移到发布数据?
  • 对于任何在未来偶然发现此问题的人,%2F 的问题是由于CGI security precaution

标签: java url servlets encode decode


【解决方案1】:

对于浏览器和服务器来说,'%2F' 和 '/' 之间存在根本区别。

HttpServletRequest 规范说(没有任何逻辑,AFAICT):

  • getContextPath:未解码
  • getPathInfo:解码
  • getPathTranslated:未解码
  • getQueryString:未解码
  • getRequestURI:未解码
  • getServletPath:解码

getPathInfo()的结果应该被解码,而getRequestURI()的结果不能被解码。如果是这样,那么您的 Servlet 容器就违反了规范(正如 Wouter Coekaerts 和 Francois Gravel 正确指出的那样)。您运行的是哪个 Tomcat 版本?

更令人困惑的是,当前的 Tomcat 版本拒绝包含某些特殊字符编码的路径,for security reasons

【讨论】:

    【解决方案2】:

    更新:此答案最初错误地指出路径中的“/”和“%2F”应始终被同等对待。它们实际上是不同的,因为路径是 / 分隔的段的列表。

    您不必区分网址的路径部分中的编码字符和未编码字符。路径中没有可以在 URL 中具有特殊含义的字符。例如。 '%2F' 必须解释为与 '/' 相同,并且访问此类 URL 的浏览器可以随意替换一个它认为合适的 URL。在它们之间产生差异是在打破 URL 编码的标准。

    在完整的 URL 中,出于不同的原因,您必须区分转义字符和非转义字符,包括:

    • 查看路径部分的结束位置。因为一个?在路径中编码不应被视为结束。
    • 在查询字符串中。因为参数的部分值可能包含“&”或“=”,...
    • 在路径中,“/”分隔两个段,而“%2F”可以包含在一个段中

    Java 可以很好地处理前两种情况:

    • getPathInfo() 仅返回路径部分,已解码
    • getParameter(String) 访问部分查询部分

    第三种情况处理得不太好。如果您想将“/”作为两个路径段的分隔符与路径段内的“/”(%2F)进行区分,那么您不能始终将路径表示为一个解码字符串。您可以将其表示为一个编码字符串(例如“foo/bar%2Fbaz”),也可以将其表示为解码段的列表(例如“foo”、“bar/baz”)。 但是因为 getPathInfo() API 承诺这样做(一个解码字符串),所以它别无选择,只能将 '/' 和 '%2F' 视为相同。

    对于通常的 Web 应用程序,这很好。如果您在极少数情况下确实需要有所作为,您可以自己解析 URL,使用getRequestURI() 获取原始版本。如果那个提供了您声称的解码的 URL,那么这意味着您正在使用的 servlet 实现中存在错误。

    【讨论】:

    • 所以我认为 / 和 %2F 之间存在差异是我的错,而按照标准没有。正如我所说,我已经通过在字符到达 url 编码部分之前消除字符来跳过这个问题,我猜这只是标准的编译方式。
    • 其实我相信路径中的“/”和“%2F”是有区别的。 RFC3986 表示路径是“/”分隔的“路径段”序列。因此,如果您想要一个包含斜杠字符的“路径段”,则必须将其编码为 %2F。例如在the Wikipedia article on percent-encoding 中说明了这一点。据我了解,有一个使用这种区别的服务器是很好的,而一个不保持这种区别的浏览器会被破坏。
    • @RobertTupelo-Schneck 你是对的。我刚刚编辑了答案来解决这个问题。
    【解决方案3】:

    根据Javadoc,getRequestURI 不应解码字符串。另一方面,getServletPath 返回一个解码的字符串。我使用 Jetty 在本地对此进行了测试,它的行为如文档中所述。

    因此,由于您描述的行为与 Sun 文档不符,因此您的情况可能存在其他问题。

    【讨论】:

    • 你说对了一部分。当我有一些 UTF-8 字符时,它保持未解码,但没有特殊字符。我正在开发 Tomcat。
    【解决方案4】:

    您似乎正在尝试做一些 RESTy(使用 Jersey)。您是否可以仅解析 URL 的前导和尾随部分以获取您要查找的数据?

    url.substring(startLength, url.length - endLength);

    【讨论】:

    • 不,我有 param1/param2/param3,它们的长度都是未知的。
    【解决方案5】:

    如果 decoded url 中有%2F,则表示 encoded url 包含%252F

    既然%2F/ 为什么不在"\/" 上拆分而不担心URL 编码?

    【讨论】:

      猜你喜欢
      • 2013-01-05
      • 2010-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-09
      • 2013-12-07
      • 1970-01-01
      相关资源
      最近更新 更多