Preventing directory traversal in nginx ingress in Kubernetes
I have the following ingress defined:
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: someName
namespace: test
annotations:
kubernetes.io/ingress.class: "ingress-public"
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "JSESSIONID"
nginx.ingress.kubernetes.io/connection-proxy-header: "keep-alive"
nginx.ingress.kubernetes.io/server-snippet: |
# block if not / or /test or /something
if ($request_uri !~* "(^\/(?:(?:test|something)(?:\/|$)|$))") {
return 404 ;
break;
}
# redirect if proto_http
if ($http_x_forwarded_proto = 'http') {
return 301 https://$host$request_uri;
break;
}
# hsts required header
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
spec:
rules:
- host: myhost.example.com
http:
paths:
- path: /
backend:
serviceName: someservice
servicePort: 80
The regex covers most cases where requests are something like /config
- as this doesn't match the regex, it returns a 404.
There are two problems that I currently have.
- Requesting
/test%2F..%2Fconfig
does NOT return a 404 even though this doesn't match the regex. - Requesting
/test/..%2Fconfig
allows you to reach/config
.
So is there either a better regex that would cover these cases, or is there a way to convert $request_uri
into an absolute uri so the regex can work on that instead of an encoded uri?
The regex is here with some test cases: https://regex101.com/r/Msu402/1
You might want to try using a location
(doc) or $uri
(doc) since both match a normalized URI. Since if is evil I would suggest a location (untested):
location ~* ^/(?!test|something) {
return 404;
}
Edit: I reread your question and it should BLOCK access to the mentioned locations in the regex. So I added the "not"...