Use HTTP security headers on all requests

This commit is contained in:
Daniel 2021-01-28 16:50:57 +01:00
parent afdb367ada
commit 89fad3d9ca
4 changed files with 38 additions and 20 deletions

View file

@ -242,6 +242,14 @@ func authenticateRequest(w http.ResponseWriter, r *http.Request, targetHandler h
}
func checkAuth(w http.ResponseWriter, r *http.Request, authRequired bool) (token *AuthToken, handled bool) {
// Return highest possible permissions in dev mode.
if devMode() {
return &AuthToken{
Read: PermitSelf,
Write: PermitSelf,
}, false
}
// Check for valid API key.
token = checkAPIKey(r)
if token != nil {
@ -462,7 +470,12 @@ func deleteSession(sessionKey string) {
}
func isReadMethod(method string) bool {
return method == http.MethodGet || method == http.MethodHead
switch method {
case http.MethodGet, http.MethodHead, http.MethodOptions:
return true
default:
return false
}
}
func parseAPIPermission(s string) (Permission, error) {

View file

@ -19,6 +19,8 @@ var (
defaultListenAddress string
configuredAPIKeys config.StringArrayOption
devMode config.BoolOption
)
func init() {
@ -79,6 +81,8 @@ func registerConfig() error {
}
configuredAPIKeys = config.GetAsStringArray(CfgAPIKeys, []string{})
devMode = config.Concurrent.GetAsBool(config.CfgDevModeKey, false)
return nil
}

View file

@ -256,6 +256,9 @@ func (eh *endpointHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
apiRequest.InputData = inputData
case http.MethodGet:
// Nothing special to do here.
case http.MethodOptions:
w.WriteHeader(http.StatusNoContent)
return
default:
http.Error(w, "Unsupported method for the actions API.", http.StatusMethodNotAllowed)
return
@ -308,7 +311,6 @@ func (eh *endpointHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// Write response.
w.Header().Set("Content-Type", apiEndpoint.MimeType+"; charset=utf-8")
w.Header().Set("Content-Length", strconv.Itoa(len(responseData)))
w.Header().Set("X-Content-Type-Options", "nosniff")
w.WriteHeader(http.StatusOK)
_, err = w.Write(responseData)
if err != nil {

View file

@ -16,17 +16,6 @@ var (
// gorilla mux
mainMux = mux.NewRouter()
// middlewares
middlewareHandler = &mwHandler{
final: mainMux,
handlers: []Middleware{
ModuleWorker,
LogTracer,
RequestLogger,
authMiddleware,
},
}
// main server and lock
server = &http.Server{}
handlerLock sync.RWMutex
@ -46,18 +35,12 @@ func RegisterHandleFunc(path string, handleFunc func(http.ResponseWriter, *http.
return mainMux.HandleFunc(path, handleFunc)
}
// RegisterMiddleware registers a middle function with the API endoint.
func RegisterMiddleware(middleware Middleware) {
handlerLock.Lock()
defer handlerLock.Unlock()
middlewareHandler.handlers = append(middlewareHandler.handlers, middleware)
}
// Serve starts serving the API endpoint.
func Serve() {
// configure server
server.Addr = listenAddressConfig()
server.Handler = &mainHandler{
// TODO: mainMux should not be modified anymore.
mux: mainMux,
}
@ -134,6 +117,22 @@ func (mh *mainHandler) handle(w http.ResponseWriter, r *http.Request) error {
return nil
}
// Add security headers.
if !devMode() {
w.Header().Set(
"Content-Security-Policy",
"default-src 'self'; "+
"style-src 'self' 'unsafe-inline'; "+
"img-src 'self' data:",
)
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")
} else {
w.Header().Set("Access-Control-Allow-Origin", "*")
}
// Handle request.
switch {
case handler != nil: