Compare commits
1 Commits
18750f107a
...
feat/add-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
706f5f6dcc |
@@ -1624,10 +1624,6 @@ authenticity.
|
|||||||
termination.
|
termination.
|
||||||
- **CORS**: The server allows all origins by default (`Access-Control-Allow-Origin: *`).
|
- **CORS**: The server allows all origins by default (`Access-Control-Allow-Origin: *`).
|
||||||
Restrict this in production via reverse proxy configuration if needed.
|
Restrict this in production via reverse proxy configuration if needed.
|
||||||
- **Content-Security-Policy**: The server sets a strict CSP header on all
|
|
||||||
responses, restricting resource loading to same-origin and disabling
|
|
||||||
dangerous features (object embeds, framing, base tag injection). The
|
|
||||||
embedded SPA works without `'unsafe-inline'` for scripts or styles.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -142,6 +142,20 @@ func (mware *Middleware) CORS() func(http.Handler) http.Handler {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Auth returns middleware that performs authentication.
|
||||||
|
func (mware *Middleware) Auth() func(http.Handler) http.Handler {
|
||||||
|
return func(next http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(
|
||||||
|
func(
|
||||||
|
writer http.ResponseWriter,
|
||||||
|
request *http.Request,
|
||||||
|
) {
|
||||||
|
mware.log.Info("AUTH: before request")
|
||||||
|
next.ServeHTTP(writer, request)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Metrics returns middleware that records HTTP metrics.
|
// Metrics returns middleware that records HTTP metrics.
|
||||||
func (mware *Middleware) Metrics() func(http.Handler) http.Handler {
|
func (mware *Middleware) Metrics() func(http.Handler) http.Handler {
|
||||||
metricsMiddleware := ghmm.New(ghmm.Config{ //nolint:exhaustruct // optional fields
|
metricsMiddleware := ghmm.New(ghmm.Config{ //nolint:exhaustruct // optional fields
|
||||||
@@ -166,36 +180,3 @@ func (mware *Middleware) MetricsAuth() func(http.Handler) http.Handler {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// cspPolicy is the Content-Security-Policy header value applied to all
|
|
||||||
// responses. The embedded SPA loads scripts and styles from same-origin
|
|
||||||
// files only (no inline scripts or inline style attributes), so a strict
|
|
||||||
// policy works without 'unsafe-inline'.
|
|
||||||
const cspPolicy = "default-src 'self'; " +
|
|
||||||
"script-src 'self'; " +
|
|
||||||
"style-src 'self'; " +
|
|
||||||
"connect-src 'self'; " +
|
|
||||||
"img-src 'self'; " +
|
|
||||||
"font-src 'self'; " +
|
|
||||||
"object-src 'none'; " +
|
|
||||||
"frame-ancestors 'none'; " +
|
|
||||||
"base-uri 'self'; " +
|
|
||||||
"form-action 'self'"
|
|
||||||
|
|
||||||
// CSP returns middleware that sets the Content-Security-Policy header on
|
|
||||||
// every response for defense-in-depth against XSS.
|
|
||||||
func (mware *Middleware) CSP() func(http.Handler) http.Handler {
|
|
||||||
return func(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(
|
|
||||||
func(
|
|
||||||
writer http.ResponseWriter,
|
|
||||||
request *http.Request,
|
|
||||||
) {
|
|
||||||
writer.Header().Set(
|
|
||||||
"Content-Security-Policy",
|
|
||||||
cspPolicy,
|
|
||||||
)
|
|
||||||
next.ServeHTTP(writer, request)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ import (
|
|||||||
|
|
||||||
const routeTimeout = 60 * time.Second
|
const routeTimeout = 60 * time.Second
|
||||||
|
|
||||||
|
// cspHeader is the Content-Security-Policy applied to the embedded web SPA.
|
||||||
|
// The SPA loads external scripts and stylesheets from the same origin only;
|
||||||
|
// all API communication uses same-origin fetch (no WebSockets).
|
||||||
|
const cspHeader = "default-src 'self'; script-src 'self'; style-src 'self'"
|
||||||
|
|
||||||
// SetupRoutes configures the HTTP routes and middleware.
|
// SetupRoutes configures the HTTP routes and middleware.
|
||||||
func (srv *Server) SetupRoutes() {
|
func (srv *Server) SetupRoutes() {
|
||||||
srv.router = chi.NewRouter()
|
srv.router = chi.NewRouter()
|
||||||
@@ -29,7 +34,6 @@ func (srv *Server) SetupRoutes() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
srv.router.Use(srv.mw.CORS())
|
srv.router.Use(srv.mw.CORS())
|
||||||
srv.router.Use(srv.mw.CSP())
|
|
||||||
srv.router.Use(middleware.Timeout(routeTimeout))
|
srv.router.Use(middleware.Timeout(routeTimeout))
|
||||||
|
|
||||||
if srv.sentryEnabled {
|
if srv.sentryEnabled {
|
||||||
@@ -134,6 +138,11 @@ func (srv *Server) setupSPA() {
|
|||||||
writer http.ResponseWriter,
|
writer http.ResponseWriter,
|
||||||
request *http.Request,
|
request *http.Request,
|
||||||
) {
|
) {
|
||||||
|
writer.Header().Set(
|
||||||
|
"Content-Security-Policy",
|
||||||
|
cspHeader,
|
||||||
|
)
|
||||||
|
|
||||||
readFS, ok := distFS.(fs.ReadFileFS)
|
readFS, ok := distFS.(fs.ReadFileFS)
|
||||||
if !ok {
|
if !ok {
|
||||||
fileServer.ServeHTTP(writer, request)
|
fileServer.ServeHTTP(writer, request)
|
||||||
|
|||||||
Reference in New Issue
Block a user