Compare commits
2 Commits
feat/add-c
...
18750f107a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
18750f107a | ||
| a98e0ca349 |
@@ -1624,6 +1624,10 @@ 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,20 +142,6 @@ 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
|
||||||
@@ -180,3 +166,36 @@ 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,11 +16,6 @@ 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()
|
||||||
@@ -34,6 +29,7 @@ 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 {
|
||||||
@@ -138,11 +134,6 @@ 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