mirror of
https://github.com/coder/coder.git
synced 2026-06-03 04:58:23 +00:00
42dd544d90
There is currently an issue with subdomain workspace apps on workspace
proxies, where if you have a workspace proxy wildcard nested beneath the
primary wildcard, cookies from the primary may be sent to the server
before cookies from the proxy specifically.
Currently:
1. Use a subdomain app via the primary proxy `*.coder.corp.com`
a. Client sends no cookies
a. Server does token smuggling flow
a. Server sets a cookie `coder_subdomain_app_session_token` on
`*.coder.corp.com`
a. Server redirects client to reload the page
a. Request should succeed as usual
1. Wait until the primary proxy's session token cookie has expired in
the database (or make it invalid yourself)
1. Use a subdomain app via a separate proxy `*.sydney.coder.corp.com`
a. Client sends `coder_subdomain_app_session_token` cookie from
`*.coder.corp.com`
a. Server validates supplied cookie, it fails because it's expired
a. Server does token smuggling flow
a. Server sets a cookie `coder_subdomain_app_session_token` on
`*.sydney.coder.corp.com`
a. Server redirects client to reload page
a. Client sends BOTH cookies.
a. The server will only process the first cookie it receives, so if the
expired cookie for the primary proxy is sent first the request will end
up in a permanent loop on step b.
The fix is to append `_{hash(wildcard_access_url)}` to the subdomain
cookies as we cannot control browser behavior further. This avoids the
conflict as each proxy will only read it's specific cookie.
39 lines
1.1 KiB
Go
39 lines
1.1 KiB
Go
package httpapi
|
|
|
|
import (
|
|
"net/textproto"
|
|
"strings"
|
|
|
|
"github.com/coder/coder/v2/codersdk"
|
|
)
|
|
|
|
// StripCoderCookies removes the session token from the cookie header provided.
|
|
func StripCoderCookies(header string) string {
|
|
header = textproto.TrimString(header)
|
|
cookies := []string{}
|
|
|
|
var part string
|
|
for len(header) > 0 { // continue since we have rest
|
|
part, header, _ = strings.Cut(header, ";")
|
|
part = textproto.TrimString(part)
|
|
if part == "" {
|
|
continue
|
|
}
|
|
name, _, _ := strings.Cut(part, "=")
|
|
if name == codersdk.SessionTokenCookie ||
|
|
name == codersdk.OAuth2StateCookie ||
|
|
name == codersdk.OAuth2RedirectCookie ||
|
|
name == codersdk.PathAppSessionTokenCookie ||
|
|
// This uses a prefix check because the subdomain cookie is unique
|
|
// per workspace proxy and is based on a hash of the workspace proxy
|
|
// subdomain hostname. See the workspaceapps package for more
|
|
// details.
|
|
strings.HasPrefix(name, codersdk.SubdomainAppSessionTokenCookie) ||
|
|
name == codersdk.SignedAppTokenCookie {
|
|
continue
|
|
}
|
|
cookies = append(cookies, part)
|
|
}
|
|
return strings.Join(cookies, "; ")
|
|
}
|