Using X-Forwarded-Uri header does not URL-decode or filter queries before matching rules
Preflight checklist
- [X] I could not find a solution in the existing issues, docs, nor discussions.
- [X] I agree to follow this project's Code of Conduct.
- [X] I have read and am following this repository's Contribution Guidelines.
- [ ] This issue affects my Ory Cloud project.
- [X] I have joined the Ory Community Slack.
- [ ] I am signed up to the Ory Security Patch Newsletter.
Describe the bug
For context, we are hosting Ory on our servers and are using Ory Oathkeeper as a decision engine behind NGINX.
When a request to our server happens, an NGINX ingress calls the decision engine to convert Kratos session cookies to an X-User-ID header. To facilitate limitations with regular NGINX ingress auth calls, we use X-Forwarded-* headers to have Oathkeeper understand the original request. We are setting the X-Forwarded-Uri header to the $request_uri variable.
It seems setting the forwarded headers results in Oathkeeper no longer filtering out queries before trying to match a rule. The URI path logs as URL encoded (see log output). I've confirmed that the oathkeeper container receives the request correctly by replacing it with netcat.
Reproducing the bug
- Install Oathkeeper and configure it to allow calls to /decisions
- Configure a rule, preferably with matching_strategy set to regex, to see a workaround
- Make a curl with parameters that should match this rule
Example rule:
[
{
"id": "example#get",
"match": {
"url": "http://localhost:4456/example",
"methods": [
"GET"
]
},
"authenticators": [
{
"handler": "noop"
}
],
"authorizer": {
"handler": "allow"
},
"mutators": [
{
"handler": "noop"
}
]
}
]
Example curl:
curl -X 'GET' 'http://localhost:4456/decisions' \
--header "X-Forwarded-Method: GET" \
--header "X-Forwarded-Proto: http" \
--header "X-Forwarded-Host: localhost:4456" \
--header "X-Forwarded-Uri: /example?foo=bar"
The curl will result in a 404 unless you drop the ?foo=bar.
Relevant log output
time=2022-09-06T07:32:18Z level=info msg=started handling request http_request=map[headers:map[accept:*/* user-agent:curl/7.74.0 x-forwarded-proto:http] host:localhost:4456 method:GET path:/decisions query:<nil> scheme:http]
ime=2022-09-06T07:32:18Z level=warning msg=Access request denied audience=application error=map[debug: message:Requested url does not match any rules reason: status:Not Found status_code:404] granted=false http_host=localhost:4456 http_method=GET http_url=http://localhost:4456/example%3Ffoo=bar http_user_agent=curl/7.74.0 service_name=ORY Oathkeeper service_version=v0.39.0
time=2022-09-06T07:32:18Z level=error msg=An error occurred while handling a request code=404 debug= details=map[] error=The requested resource could not be found reason= request-id= status=404 writer=JSON
time=2022-09-06T07:32:18Z level=info msg=completed handling request http_request=map[headers:map[accept:*/* user-agent:curl/7.74.0 x-forwarded-proto:http] host:localhost:4456 method:GET path:/example%3Ffoo=bar query:<nil> scheme:http] http_response=map[status:404 text_status:Not Found took:247.054µs]
Relevant configuration
version: v0.39.2
serve:
api:
port: 4456
access_rules:
matching_strategy: regexp
repositories:
- file://path/to/rule.json
errors:
fallback:
- json
log:
level: debug
leak_sensitive_values: true
authenticators:
noop:
enabled: true
authorizers:
allow:
enabled: true
mutators:
noop:
enabled: true
Version
v0.39.2
On which operating system are you observing this issue?
Linux
In which environment are you deploying?
Kubernetes
Additional Context
The mentioned workaround is to set the match URL to
http://localhost:4456/example<((\\%F3).*)?>.