fix: limit OAuth redirects to local paths (#14585)

- This prevents a malicious user from crafting a redirect
  URL to a nefarious site under their control.
This commit is contained in:
Jon Ayers
2024-09-10 15:58:50 +01:00
committed by GitHub
parent 2a9234e9ba
commit 328e69629c
8 changed files with 183 additions and 20 deletions

View File

@ -4,6 +4,7 @@ import (
"context"
"fmt"
"net/http"
"net/url"
"reflect"
"github.com/go-chi/chi/v5"
@ -85,6 +86,15 @@ func ExtractOAuth2(config promoauth.OAuth2Config, client *http.Client, authURLOp
code := r.URL.Query().Get("code")
state := r.URL.Query().Get("state")
redirect := r.URL.Query().Get("redirect")
if redirect != "" {
// We want to ensure that we're only ever redirecting to the application.
// We could be more strict here and check to see if the host matches
// the host of the AccessURL but ultimately as long as our redirect
// url omits a host we're ensuring that we're routing to a path
// local to the application.
redirect = uriFromURL(redirect)
}
if code == "" {
// If the code isn't provided, we'll redirect!
@ -119,7 +129,7 @@ func ExtractOAuth2(config promoauth.OAuth2Config, client *http.Client, authURLOp
// an old redirect could apply!
http.SetCookie(rw, &http.Cookie{
Name: codersdk.OAuth2RedirectCookie,
Value: r.URL.Query().Get("redirect"),
Value: redirect,
Path: "/",
HttpOnly: true,
SameSite: http.SameSiteLaxMode,
@ -150,7 +160,6 @@ func ExtractOAuth2(config promoauth.OAuth2Config, client *http.Client, authURLOp
return
}
var redirect string
stateRedirect, err := r.Cookie(codersdk.OAuth2RedirectCookie)
if err == nil {
redirect = stateRedirect.Value
@ -302,3 +311,12 @@ func ExtractOAuth2ProviderAppSecret(db database.Store) func(http.Handler) http.H
})
}
}
func uriFromURL(u string) string {
uri, err := url.Parse(u)
if err != nil {
return "/"
}
return uri.RequestURI()
}