Loading…
Loading…
Explains how the platform normalizes incoming request paths for security authorization checks to prevent allow-list bypass vulnerabilities.
The RoutedRequestPath component is a security utility that produces a canonical, normalized string representation of an HTTP request's path. Its primary purpose is to resolve a class of security vulnerabilities where the path used for authorization checks differs from the path the underlying web framework uses for routing.
This component solves the problem of "allow-list bypass" attacks. Such attacks exploit variations in a request URI—such as percent-encoding (%70 instead of p) or matrix parameters (/path;param=val/resource)—to circumvent security policies that match on simple string representations of the path.
RoutedRequestPath is designed to be used by security filters that execute before the main request dispatcher. It takes an HttpServletRequest as input and produces a normalized path string. Authorization logic must use this string to ensure that security decisions are based on the exact same path interpretation that the routing engine will use. If a path cannot be unambiguously resolved, the component signals this, allowing the caller to fail-closed and deny the request.
The RoutedRequestPath component derives the canonical path by replicating the normalization and parsing logic of the platform's Spring-based routing framework. This ensures that the path used for authorization is identical to the path used for dispatching the request to a handler.
The process follows these steps:
RoutedRequestPath.of() is called with an HttpServletRequest.ServletRequestPathUtils.parse() utility to parse the raw request URI into a RequestPath object. This step does not use a cache, ensuring it does not interfere with later processing by the DispatcherServlet.pathWithinApplication(), which is a PathContainer representation of the path. This removes any server context path or servlet prefix, focusing only on the part of the path relevant to application routing.PathContainer is then rendered into a final string according to a strict set of rules. This rendering logic is the core of the component's security function.The rendering logic performs the following transformations:
valueToMatch() representation. This value is percent-decoded, and any matrix parameters (e.g., ;key=value) are stripped.. or .. or that contain an encoded path separator (/). These are characteristics of path traversal or path confusion attacks.//) are collapsed into a single /./ on the original path is kept in the output, as the routing engine treats paths with and without a trailing slash differently.If at any point parsing fails or a validation rule is violated, the component returns null, signaling to the caller that the path is malformed or ambiguous and the request should be rejected.
flowchart TD
subgraph RoutedRequestPath.of()
A[HttpServletRequest] --> B{ServletRequestPathUtils.parse(request)};
B --> C[RequestPath];
C --> D{pathWithinApplication()};
D --> E[PathContainer];
E --> F{Render & Validate};
end
subgraph "Fail-Closed Conditions"
style "Fail-Closed Conditions" fill:#fdd,stroke:#f00,stroke-width:2px
B -- on any RuntimeException --> G[return null];
F -- on validation failure --> G[return null];
end
F -- on success --> H[Canonical Path String];
A -.-> G;
subgraph Caller
H --> I{Authorization Logic};
G --> I;
I --> J{Decision: Allow / Deny};
endRoutedRequestPath is a final utility class with a single static method and cannot be instantiated.
public static String of(HttpServletRequest request)Returns the canonical, routed path for a given request, or null if the path cannot be resolved unambiguously.
request (HttpServletRequest): The incoming HTTP servlet request to analyze.String containing the normalized path for authorization checks.null if the path is ambiguous, malformed, or invalid. Callers must treat a null return value as a fail-closed condition, typically by denying the request or applying the most restrictive security policy.The following table illustrates how RoutedRequestPath normalizes various input URIs.
| Raw Request Path | Normalized Output | Rationale |
|---|---|---|
/admin/v1/resource | /admin/v1/resource | A standard, canonical path remains unchanged. |
/admin/v1/%70ermission-bindings | /admin/v1/permission-bindings | Percent-encoded characters are decoded. |
/admin/v1;x=1/permission-bindings | /admin/v1/permission-bindings | Matrix parameters (...;x=1/...) are stripped from path segments. |
/admin//v1/resource | /admin/v1/resource | Runs of path separators are collapsed into a single separator. |
/admin/v1/resource/ | /admin/v1/resource/ | A trailing slash is preserved. |
/admin/v1/../resource | null | Path segments containing .. are invalid and cause a fail-closed response. |
/admin/v1/res%2Fource | null | Path segments containing an encoded separator (%2F -> /) are invalid and cause a fail-closed response. |
Malformed URI (e.g., /path/%ZZ) | null | Any parsing exception, such as from a malformed percent-escape, results in a fail-closed response. |
The RoutedRequestPath.of() method is designed to be fail-closed, returning null whenever a path cannot be safely and unambiguously determined. Callers must interpret a null result as a signal to reject the request.
A null value is returned under the following circumstances:
HttpServletRequest object or its URI is null.RuntimeException is thrown during path parsing. This includes, but is not limited to:
IllegalArgumentException from a malformed percent-encoding sequence (e.g., /path/%GZ).NullPointerException if the servlet container provides an invalid HttpServletMapping./). Example: res%2Fource.. (a single dot)... (a double dot).IMPORTANT
A null return from RoutedRequestPath.of() indicates a potentially malicious or malformed request. Authorization systems using this component must treat null as a definitive failure and deny the request.
RoutedRequestPath. The filter uses the normalized path to make consistent and secure authorization decisions for administrative endpoints.