Macaron: convert CSP middleware (#37672)

pull/37201/head
Serge Zaitsev 4 years ago committed by GitHub
parent 377b323faf
commit 0dfac9c3aa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      pkg/api/http_server.go
  2. 71
      pkg/middleware/csp.go
  3. 2
      pkg/middleware/middleware_test.go

@ -375,7 +375,7 @@ func (hs *HTTPServer) addMiddlewaresAndStaticRoutes() {
} }
m.Use(middleware.HandleNoCacheHeader) m.Use(middleware.HandleNoCacheHeader)
m.Use(middleware.AddCSPHeader(hs.Cfg, hs.log)) m.UseMiddleware(middleware.AddCSPHeader(hs.Cfg, hs.log))
for _, mw := range hs.middlewares { for _, mw := range hs.middlewares {
m.Use(mw) m.Use(mw)

@ -10,45 +10,44 @@ import (
"strings" "strings"
"github.com/grafana/grafana/pkg/infra/log" "github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models" "github.com/grafana/grafana/pkg/services/contexthandler"
"github.com/grafana/grafana/pkg/setting" "github.com/grafana/grafana/pkg/setting"
macaron "gopkg.in/macaron.v1"
) )
// AddCSPHeader adds the Content Security Policy header. // AddCSPHeader adds the Content Security Policy header.
func AddCSPHeader(cfg *setting.Cfg, logger log.Logger) macaron.Handler { func AddCSPHeader(cfg *setting.Cfg, logger log.Logger) func(http.Handler) http.Handler {
return func(w http.ResponseWriter, req *http.Request, c *macaron.Context) { return func(next http.Handler) http.Handler {
if !cfg.CSPEnabled { return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
return if !cfg.CSPEnabled {
} next.ServeHTTP(rw, req)
return
logger.Debug("Adding CSP header to response", "cfg", fmt.Sprintf("%p", cfg)) }
ctx, ok := c.Data["ctx"].(*models.ReqContext) logger.Debug("Adding CSP header to response", "cfg", fmt.Sprintf("%p", cfg))
if !ok {
panic("Failed to convert context into models.ReqContext") ctx := contexthandler.FromContext(req.Context())
} if cfg.CSPTemplate == "" {
logger.Debug("CSP template not configured, so returning 500")
if cfg.CSPTemplate == "" { ctx.JsonApiErr(500, "CSP template has to be configured", nil)
logger.Debug("CSP template not configured, so returning 500") return
ctx.JsonApiErr(500, "CSP template has to be configured", nil) }
return
} var buf [16]byte
if _, err := io.ReadFull(rand.Reader, buf[:]); err != nil {
var buf [16]byte logger.Error("Failed to generate CSP nonce", "err", err)
if _, err := io.ReadFull(rand.Reader, buf[:]); err != nil { ctx.JsonApiErr(500, "Failed to generate CSP nonce", err)
logger.Error("Failed to generate CSP nonce", "err", err) }
ctx.JsonApiErr(500, "Failed to generate CSP nonce", err)
} nonce := base64.RawStdEncoding.EncodeToString(buf[:])
val := strings.ReplaceAll(cfg.CSPTemplate, "$NONCE", fmt.Sprintf("'nonce-%s'", nonce))
nonce := base64.RawStdEncoding.EncodeToString(buf[:])
val := strings.ReplaceAll(cfg.CSPTemplate, "$NONCE", fmt.Sprintf("'nonce-%s'", nonce)) re := regexp.MustCompile(`^\w+:(//)?`)
rootPath := re.ReplaceAllString(cfg.AppURL, "")
re := regexp.MustCompile(`^\w+:(//)?`) val = strings.ReplaceAll(val, "$ROOT_PATH", rootPath)
rootPath := re.ReplaceAllString(cfg.AppURL, "") rw.Header().Set("Content-Security-Policy", val)
val = strings.ReplaceAll(val, "$ROOT_PATH", rootPath) ctx.RequestNonce = nonce
w.Header().Set("Content-Security-Policy", val) logger.Debug("Successfully generated CSP nonce", "nonce", nonce)
ctx.RequestNonce = nonce next.ServeHTTP(rw, req)
logger.Debug("Successfully generated CSP nonce", "nonce", nonce) })
} }
} }

@ -632,7 +632,7 @@ func middlewareScenario(t *testing.T, desc string, fn scenarioFunc, cbs ...func(
sc.m = macaron.New() sc.m = macaron.New()
sc.m.Use(AddDefaultResponseHeaders(cfg)) sc.m.Use(AddDefaultResponseHeaders(cfg))
sc.m.Use(AddCSPHeader(cfg, logger)) sc.m.UseMiddleware(AddCSPHeader(cfg, logger))
sc.m.Use(macaron.Renderer(macaron.RenderOptions{ sc.m.Use(macaron.Renderer(macaron.RenderOptions{
Directory: viewsPath, Directory: viewsPath,
Delims: macaron.Delims{Left: "[[", Right: "]]"}, Delims: macaron.Delims{Left: "[[", Right: "]]"},

Loading…
Cancel
Save