1. Introduction
1.介绍
When we develop web services, we may need to deal with complex or unexpected URL paths that can contain slashes. As a consequence, we may encounter issues with the web servers or frameworks we are using.
当我们开发Web服务时,我们可能需要处理复杂或意外的URL路径,这些路径可能包含斜线。因此,我们可能会遇到我们正在使用的网络服务器或框架的问题。
Spring specifically can be a bit tricky in this regard due to the default configurations that it provides.
特别是Spring,由于它提供的默认配置,在这方面可能有点棘手。
In this tutorial, we’ll show some common solutions and recommendations for handling URLs with slashes in Spring. We’ll also see why we shouldn’t use some common hacks to work around these issues. Keep reading to know more about it!
在本教程中,我们将展示一些在Spring中处理带有斜线的URL的常见解决方案和建议。我们还将看到为什么我们不应该使用一些常见的黑客来解决这些问题。请继续阅读以了解更多信息!
2. Parse the Request Manually
2.手动解析请求
In our web services, sometimes we need to map all the requests under a certain path to the same endpoint. To make matters worse, we may not know what the rest of the path will look like. We might also need to somehow receive this path as a parameter in order to use it afterward.
在我们的Web服务中,有时我们需要将某一路径下的所有请求映射到同一个端点。更糟糕的是,我们可能不知道路径的其余部分会是什么样子。我们可能还需要以某种方式接收这个路径作为一个参数,以便事后使用它。
Let’s say that we can receive requests with any path under /mypaths:
假设我们可以接收带有/mypaths下任何路径的请求。
http://localhost:8080/mypaths/any/custom/path
And suppose we want to store all these different paths in a database to know what requests we’re receiving.
假设我们想把所有这些不同的路径存储在数据库中,以了解我们收到了哪些请求。
The first solution that will probably come to our minds is to capture the dynamic part of the path into a PathVariable:
我们可能会想到的第一个解决方案是将路径的动态部分捕捉到一个PathVariable中。
@GetMapping("mypaths/{anything}")
public String pathVariable(@PathVariable("anything") String anything) {
return anything;
}
Unfortunately, we soon find out that this returns a 404 if the PathVariable contains a slash. The slash character is the URI standard path delimiter, and all that goes after it counts as a new level in the path hierarchy. As expected, Spring follows this standard.
不幸的是,我们很快发现,如果PathVariable包含一个斜线,则返回404。斜线字符是URI标准路径分隔符,它之后的所有内容都算作路径层次结构中的一个新层次。正如预期的那样,Spring遵循这个标准。
We can easily solve this by creating a fallback for all the requests under a certain path by using the ** wildcard:
我们可以通过使用**通配符为某一路径下的所有请求创建一个回退机制来轻松解决这个问题。
@GetMapping("all/**")
public String allDirectories(HttpServletRequest request) {
return request.getRequestURI()
.split(request.getContextPath() + "/all/")[1];
}
Then we have to parse the URI ourselves in order to get the part of the path we’re interested in.
然后我们必须自己解析URI,以获得我们感兴趣的那部分路径。
This solution is very convenient when working with URL-like parameters, but as we’ll see in the next section, it’s not enough for some other cases.
这种解决方案在处理类似URL的参数时非常方便,但正如我们在下一节所看到的,它对其他一些情况是不够的。
3. Use Query Parameters
3.使用查询参数
In contrast to our previous example, there are other cases where we’re not just mapping different paths but receiving any String as a parameter in the URL.
与我们之前的例子相比,还有其他情况,我们不仅仅是映射不同的路径,而是接收任何String作为URL中的参数。
Let’s imagine that in our previous example, we make a request with a path parameter that contains consecutive slashes:
让我们想象一下,在我们之前的例子中,我们提出了一个包含连续斜线的路径参数的请求。
http://localhost:8080/all/http://myurl.com
At first, we could think that this should work, but we soon realize that our controller returns http:/myurl.com. This happens because Spring Security normalizes the URLs and replaces any double-slash with a single one.
起初,我们可以认为这应该是可行的,但我们很快意识到,我们的控制器返回http:/myurl.com。这是因为Spring Security对URL进行了规范化处理,并将任何双斜杠替换为单斜杠。
Spring also normalizes other sequences in URLs, such as path traversals. It takes these precautions to prevent malicious URLs from bypassing the defined security constraints, as explained in the official Spring Security documentation.
Spring还对URL中的其他序列进行规范化处理,例如路径遍历。它采取这些预防措施以防止恶意的URL绕过已定义的安全约束,如官方Spring安全文档中所解释的。
In these cases, it’s strongly recommended to use query parameters instead:
在这些情况下,强烈建议使用查询参数来代替。
@GetMapping("all")
public String queryParameter(@RequestParam("param") String param) {
return param;
}
This way, we can receive any String parameter without these security restrictions, and our web service will be more robust and secure.
这样,我们就可以接收任何String参数,而没有这些安全限制,我们的网络服务将更加强大和安全。
4. Avoid Workarounds
4.避免变通
The solutions we’ve presented may imply some changes in our mappings design. This could tempt us to use some common workarounds to make our original endpoints work when receiving slashes in the URLs.
我们提出的解决方案可能意味着在我们的映射设计中会有一些变化。这可能会诱使我们使用一些常见的变通方法,使我们原来的端点在接收到URL中的斜线时能够正常工作。
The most common workaround is probably to encode the slashes in the path parameters. However, some security vulnerabilities were reported in the past and most web and application servers reacted to it by disallowing the encoded slashes by default. It’s still possible to change this behavior just by changing the corresponding setting, like in Tomcat.
最常见的解决方法可能是对路径参数中的斜线进行编码。然而,过去曾报告过一些安全漏洞,大多数Web和应用程序服务器对此的反应是默认不允许编码斜线。仅仅通过改变相应的设置,仍然可以改变这种行为,比如在Tomcat。
Others like Apache Server went a bit further and introduced an option to allow encoded slashes without decoding them so that they’re not interpreted as path delimiters. In any case, this is not recommended and it can introduce potential security risks.
其他诸如Apache Server等则更进一步,引入了一个选项,允许编码斜线而不对其进行解码,这样就不会将其解释为路径分隔符。在任何情况下,这都是不推荐的,它可能会带来潜在的安全风险。
On the other hand, web frameworks also take some precautions. As we’ve seen before, Spring adds some mechanisms as protection against less strict servlet containers. So, in case we allow encoded slashes in our server, we still have to allow them in Spring.
另一方面,Web框架也采取了一些预防措施。正如我们之前看到的,Spring增加了一些机制,作为对不太严格的Servlet容器的保护。因此,如果我们在服务器中允许编码斜线,我们仍然必须在Spring中允许它们。
Finally, there are other kinds of workarounds like changing the URI normalization that Spring provides by default. As before, we should be very cautious if we change these defaults.
最后,还有其他类型的变通方法,比如改变Spring默认提供的URI规范化。和以前一样,如果我们改变这些默认值,我们应该非常谨慎。
5. Conclusion
5.结论
In this short article, we’ve shown some solutions for dealing with slashes in URLs in Spring. We’ve also introduced some security problems that can arise if we change the default configurations of servers or frameworks like Spring.
在这篇短文中,我们展示了一些在Spring中处理URL中斜线的解决方案。我们还介绍了一些安全问题,如果我们改变服务器或框架(如Spring)的默认配置,就会出现这些问题。
As a rule of thumb, query parameters are usually the best solution to deal with slashes in URLs.
作为一条经验法则,查询参数通常是处理URL中斜线的最佳解决方案。
As always, the full source code for the examples is available over on GitHub.
一如既往,这些示例的完整源代码可在GitHub上获得over。