mirror of
https://github.com/safing/portbase
synced 2025-09-04 03:29:59 +00:00
Merge pull request #172 from safing/fix/cors-preflight
Fix CORS preflight checks requiring authentication
This commit is contained in:
commit
ce02b26ff5
1 changed files with 50 additions and 31 deletions
|
@ -105,11 +105,28 @@ func (mh *mainHandler) handle(w http.ResponseWriter, r *http.Request) error {
|
||||||
tracer.Submit()
|
tracer.Submit()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Add security headers.
|
||||||
|
w.Header().Set("Referrer-Policy", "no-referrer")
|
||||||
|
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||||
|
w.Header().Set("X-Frame-Options", "deny")
|
||||||
|
w.Header().Set("X-XSS-Protection", "1; mode=block")
|
||||||
|
w.Header().Set("X-DNS-Prefetch-Control", "off")
|
||||||
|
|
||||||
|
// Add CSP Header in production mode.
|
||||||
|
if !devMode() {
|
||||||
|
w.Header().Set(
|
||||||
|
"Content-Security-Policy",
|
||||||
|
"default-src 'self'; "+
|
||||||
|
"connect-src https://*.safing.io 'self'; "+
|
||||||
|
"style-src 'self' 'unsafe-inline'; "+
|
||||||
|
"img-src 'self' data:",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Check Cross-Origin Requests.
|
// Check Cross-Origin Requests.
|
||||||
isCrossSite := false
|
|
||||||
origin := r.Header.Get("Origin")
|
origin := r.Header.Get("Origin")
|
||||||
|
isPreflighCheck := false
|
||||||
if origin != "" {
|
if origin != "" {
|
||||||
isCrossSite = true
|
|
||||||
|
|
||||||
// Parse origin URL.
|
// Parse origin URL.
|
||||||
originURL, err := url.Parse(origin)
|
originURL, err := url.Parse(origin)
|
||||||
|
@ -125,6 +142,12 @@ func (mh *mainHandler) handle(w http.ResponseWriter, r *http.Request) error {
|
||||||
// Origin (with port) matches Host.
|
// Origin (with port) matches Host.
|
||||||
case originURL.Hostname() == r.Host:
|
case originURL.Hostname() == r.Host:
|
||||||
// Origin (without port) matches Host.
|
// Origin (without port) matches Host.
|
||||||
|
case originURL.Scheme == "chrome-extension":
|
||||||
|
// Allow access for the browser extension
|
||||||
|
// TODO(ppacher):
|
||||||
|
// This currently allows access from any browser extension.
|
||||||
|
// Can we reduce that to only our browser extension?
|
||||||
|
// Also, what do we need to support Firefox?
|
||||||
case devMode() &&
|
case devMode() &&
|
||||||
utils.StringInSlice(allowedDevCORSOrigins, originURL.Hostname()):
|
utils.StringInSlice(allowedDevCORSOrigins, originURL.Hostname()):
|
||||||
// We are in dev mode and the request is coming from the allowed
|
// We are in dev mode and the request is coming from the allowed
|
||||||
|
@ -138,6 +161,22 @@ func (mh *mainHandler) handle(w http.ResponseWriter, r *http.Request) error {
|
||||||
// If the Host header has a port, and the Origin does not, requests will
|
// If the Host header has a port, and the Origin does not, requests will
|
||||||
// also end up here, as we cannot properly check for equality.
|
// also end up here, as we cannot properly check for equality.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add Cross-Site Headers now as we need them in any case now.
|
||||||
|
w.Header().Set("Access-Control-Allow-Origin", origin)
|
||||||
|
w.Header().Set("Access-Control-Allow-Methods", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Headers", "*")
|
||||||
|
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||||
|
w.Header().Set("Access-Control-Expose-Headers", "*")
|
||||||
|
w.Header().Set("Access-Control-Max-Age", "60")
|
||||||
|
w.Header().Add("Vary", "Origin")
|
||||||
|
|
||||||
|
// if there's a Access-Control-Request-Method header this is a Preflight check.
|
||||||
|
// In that case, we will just check if the preflighMethod is allowed and then return
|
||||||
|
// success here
|
||||||
|
if preflighMethod := r.Header.Get("Access-Control-Request-Method"); r.Method == http.MethodOptions && preflighMethod != "" {
|
||||||
|
isPreflighCheck = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean URL.
|
// Clean URL.
|
||||||
|
@ -184,6 +223,15 @@ func (mh *mainHandler) handle(w http.ResponseWriter, r *http.Request) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// At this point we know the method is allowed and there's a handler for the request.
|
||||||
|
// If this is just a CORS-Preflight, we'll accept the request with StatusOK now.
|
||||||
|
// There's no point in trying to authenticate the request because the Browser will
|
||||||
|
// not send authentication along a preflight check.
|
||||||
|
if isPreflighCheck && handler != nil {
|
||||||
|
lrw.WriteHeader(http.StatusOK)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Check authentication.
|
// Check authentication.
|
||||||
apiRequest.AuthToken = authenticateRequest(lrw, r, handler, readMethod)
|
apiRequest.AuthToken = authenticateRequest(lrw, r, handler, readMethod)
|
||||||
if apiRequest.AuthToken == nil {
|
if apiRequest.AuthToken == nil {
|
||||||
|
@ -199,35 +247,6 @@ func (mh *mainHandler) handle(w http.ResponseWriter, r *http.Request) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add security headers.
|
|
||||||
w.Header().Set("Referrer-Policy", "no-referrer")
|
|
||||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
|
||||||
w.Header().Set("X-Frame-Options", "deny")
|
|
||||||
w.Header().Set("X-XSS-Protection", "1; mode=block")
|
|
||||||
w.Header().Set("X-DNS-Prefetch-Control", "off")
|
|
||||||
|
|
||||||
// Add CSP Header in production mode.
|
|
||||||
if !devMode() {
|
|
||||||
w.Header().Set(
|
|
||||||
"Content-Security-Policy",
|
|
||||||
"default-src 'self'; "+
|
|
||||||
"connect-src https://*.safing.io 'self'; "+
|
|
||||||
"style-src 'self' 'unsafe-inline'; "+
|
|
||||||
"img-src 'self' data:",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add Cross-Site Headers when handling Cross-Site Requests.
|
|
||||||
if isCrossSite {
|
|
||||||
w.Header().Set("Access-Control-Allow-Origin", origin)
|
|
||||||
w.Header().Set("Access-Control-Allow-Methods", "*")
|
|
||||||
w.Header().Set("Access-Control-Allow-Headers", "*")
|
|
||||||
w.Header().Set("Access-Control-Allow-Credentials", "true")
|
|
||||||
w.Header().Set("Access-Control-Expose-Headers", "*")
|
|
||||||
w.Header().Set("Access-Control-Max-Age", "60")
|
|
||||||
w.Header().Add("Vary", "Origin")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if we have a handler.
|
// Check if we have a handler.
|
||||||
if handler == nil {
|
if handler == nil {
|
||||||
http.Error(lrw, "Not found.", http.StatusNotFound)
|
http.Error(lrw, "Not found.", http.StatusNotFound)
|
||||||
|
|
Loading…
Add table
Reference in a new issue