reitit icon indicating copy to clipboard operation
reitit copied to clipboard

redirect-trailing-slash-handler can end up redirecting to external URL

Open svdm opened this issue 5 years ago • 0 comments

This requires a specific route configuration that includes a route that can potentially match a path that starts with //, for example in this minimal setup:

(def app
  (ring/ring-handler
    (ring/router
     [["/ping" {:get (constantly {:status 200, :body "ping"})}]
      ["/*" {:get (constantly nil)}]]
     {:conflicts (fn [c])})
    (ring/redirect-trailing-slash-handler {:method :strip})))

A request like the following can end up redirecting to an absolute URL outside the app instead of to the relative path that the slash-handler is intending:

(app {:uri "//metosin.github.io/reitit/" :request-method :get})
; {:status 301, :headers {"Location" "//metosin.github.io/reitit"}, :body ""}
;; NB: Browsers will interpret this as a redirect to https://metosin.github.io/reitit

What happens is the following, taking //foo/ as a (shorter) example:

  1. The wildcard route matches //foo/, but returns nil
  2. The URL ends with a /, so the slash-handler will strip it
  3. The slash-handler uses match-by-path with the stripped URL //foo, this matches the wildcard route (again)
  4. The slash-handler returns Location: //foo in its response, sending the client off to a strange place.

Of course in the real world you wouldn't have a wildcard route that always returns nil, but one could have e.g. a resource-handler on that route that returns nil for any path that does not match a resource filename.

This behaviour could be fixed by stripping multiple slashes at the start of the path before returning it as Location in the slash handler.

svdm avatar Nov 26 '19 09:11 svdm