Skip to content

Commit a273698

Browse files
committed
docs(web): add guidance on using RoutingContext#normalizedPath() for security-sensitive path checks
Signed-off-by: Matthaios Stavrou <[email protected]>
1 parent 1536980 commit a273698

File tree

2 files changed

+51
-6
lines changed

2 files changed

+51
-6
lines changed

vertx-web/src/main/asciidoc/index.adoc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,41 @@ to {@link io.vertx.ext.web.Router#handle}.
167167

168168
So, that's the basics. Now we'll look at things in more detail:
169169

170+
== Raw path vs normalized path
171+
172+
When working with routes, it is important to understand that
173+
`HttpServerRequest#path()` returns the *raw* request path as it was
174+
sent by the client. This value may still contain segments such as
175+
`.` or `..`, or repeated `/` characters.
176+
177+
Vert.x Web internally uses a *normalized* version of the path when
178+
matching routes. To obtain this normalized value inside a handler,
179+
use `RoutingContext#normalizedPath()`:
180+
181+
[source,java]
182+
----
183+
router.route("/secured/*").handler(ctx -> {
184+
// Raw path as sent by the client (may contain "..")
185+
String raw = ctx.request().path();
186+
187+
// Normalized path as used by the router for matching
188+
String normalized = ctx.normalizedPath();
189+
190+
// For security-sensitive checks, prefer the normalized path
191+
if ("/secured/data".equals(normalized)) {
192+
// ...
193+
}
194+
});
195+
----
196+
197+
[NOTE]
198+
====
199+
For logging or authorization decisions that depend on the request path,
200+
prefer `RoutingContext#normalizedPath()` instead of `HttpServerRequest#path()`,
201+
to avoid surprises with paths like `/secured/../secured/data`.
202+
====
203+
204+
170205
== Handling requests and calling the next handler
171206

172207
When Vert.x-Web decides to route a request to a matching route, it calls the handler of the route passing in an instance

vertx-web/src/main/java/io/vertx/ext/web/RoutingContext.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,15 +178,25 @@ public interface RoutingContext {
178178
@Nullable Route currentRoute();
179179

180180
/**
181-
* Normalizes a path as per <a href="http://tools.ietf.org/html/rfc3986#section-5.2.4>rfc3986</a>.
181+
* Returns the normalized path of the current request.
182182
* <p>
183-
* There are 2 extra transformations that are not part of the spec but kept for backwards compatibility:
183+
* Unlike {@link io.vertx.core.http.HttpServerRequest#path()}, which returns
184+
* the <em>raw</em> path as sent by the client, this value is normalized for
185+
* routing purposes. The normalization process:
186+
* <ul>
187+
* <li>resolves dot-segments such as {@code ".."} and {@code "."},</li>
188+
* <li>collapses multiple {@code '/'} characters into a single slash,</li>
189+
* <li>ensures the path always starts with {@code '/'},</li>
190+
* <li>normalizes {@code null} paths to {@code "/"}</li>
191+
* </ul>
184192
* <p>
185-
* double slash // will be converted to single slash and the path will always start with slash.
186-
* <p>
187-
* Null paths are normalized to {@code /}.
193+
* This is the value used internally by Vert.x Web when matching routes. For
194+
* any security-sensitive checks or custom authorization logic, prefer using
195+
* this normalized path instead of {@code request().path()}, as the raw path
196+
* may still contain traversal-like sequences (e.g. {@code "/a/../b"}) that
197+
* resolve to the same route.
188198
*
189-
* @return normalized path
199+
* @return the normalized path
190200
*/
191201
String normalizedPath();
192202

0 commit comments

Comments
 (0)