fix(server): missing modern security headers (#3288)
This fixes an issue with missing modern security headers such as the X-Content-Type-Options, Referer-Policy, etc.pull/3250/head^2
parent
7f0e758188
commit
556a115c83
|
@ -7,8 +7,8 @@ import (
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AssetOverrideMiddleware allows overriding and serving of specific embedded assets from disk.
|
// AssetOverride allows overriding and serving of specific embedded assets from disk.
|
||||||
func AssetOverrideMiddleware(root string, strip int, next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
func AssetOverride(root string, strip int, next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
return func(ctx *fasthttp.RequestCtx) {
|
return func(ctx *fasthttp.RequestCtx) {
|
||||||
if root == "" {
|
if root == "" {
|
||||||
next(ctx)
|
next(ctx)
|
||||||
|
|
|
@ -30,6 +30,10 @@ var (
|
||||||
headerAccessControlMaxAge = []byte(fasthttp.HeaderAccessControlMaxAge)
|
headerAccessControlMaxAge = []byte(fasthttp.HeaderAccessControlMaxAge)
|
||||||
headerAccessControlRequestHeaders = []byte(fasthttp.HeaderAccessControlRequestHeaders)
|
headerAccessControlRequestHeaders = []byte(fasthttp.HeaderAccessControlRequestHeaders)
|
||||||
headerAccessControlRequestMethod = []byte(fasthttp.HeaderAccessControlRequestMethod)
|
headerAccessControlRequestMethod = []byte(fasthttp.HeaderAccessControlRequestMethod)
|
||||||
|
|
||||||
|
headerXContentTypeOptions = []byte(fasthttp.HeaderXContentTypeOptions)
|
||||||
|
headerReferrerPolicy = []byte(fasthttp.HeaderReferrerPolicy)
|
||||||
|
headerPermissionsPolicy = []byte("Permissions-Policy")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -40,6 +44,10 @@ var (
|
||||||
headerValueVaryWildcard = []byte("Accept-Encoding")
|
headerValueVaryWildcard = []byte("Accept-Encoding")
|
||||||
headerValueOriginWildcard = []byte("*")
|
headerValueOriginWildcard = []byte("*")
|
||||||
headerValueZero = []byte("0")
|
headerValueZero = []byte("0")
|
||||||
|
|
||||||
|
headerValueNoSniff = []byte("nosniff")
|
||||||
|
headerValueStrictOriginCrossOrigin = []byte("strict-origin-when-cross-origin")
|
||||||
|
headerValueCohort = []byte("interest-cohort=()")
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package middlewares
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SecurityHeaders middleware adds several modern recommended security headers with safe values.
|
||||||
|
func SecurityHeaders(next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
|
return func(ctx *fasthttp.RequestCtx) {
|
||||||
|
ctx.Response.Header.SetBytesKV(headerXContentTypeOptions, headerValueNoSniff)
|
||||||
|
ctx.Response.Header.SetBytesKV(headerReferrerPolicy, headerValueStrictOriginCrossOrigin)
|
||||||
|
ctx.Response.Header.SetBytesKV(headerPermissionsPolicy, headerValueCohort)
|
||||||
|
|
||||||
|
next(ctx)
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogRequestMiddleware logs the query that is being treated.
|
// LogRequest logs the query that is being treated.
|
||||||
func LogRequestMiddleware(next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
func LogRequest(next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
return func(ctx *fasthttp.RequestCtx) {
|
return func(ctx *fasthttp.RequestCtx) {
|
||||||
autheliaCtx := &AutheliaCtx{RequestCtx: ctx}
|
autheliaCtx := &AutheliaCtx{RequestCtx: ctx}
|
||||||
logger := NewRequestLogger(autheliaCtx)
|
logger := NewRequestLogger(autheliaCtx)
|
||||||
|
|
|
@ -13,7 +13,7 @@ func TestShouldCallNextFunction(t *testing.T) {
|
||||||
f := func(ctx *fasthttp.RequestCtx) { val = true }
|
f := func(ctx *fasthttp.RequestCtx) { val = true }
|
||||||
|
|
||||||
context := &fasthttp.RequestCtx{}
|
context := &fasthttp.RequestCtx{}
|
||||||
LogRequestMiddleware(f)(context)
|
LogRequest(f)(context)
|
||||||
|
|
||||||
assert.Equal(t, true, val)
|
assert.Equal(t, true, val)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StripPathMiddleware strips the first level of a path.
|
// StripPath strips the first level of a path.
|
||||||
func StripPathMiddleware(path string, next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
func StripPath(path string, next fasthttp.RequestHandler) fasthttp.RequestHandler {
|
||||||
return func(ctx *fasthttp.RequestCtx) {
|
return func(ctx *fasthttp.RequestCtx) {
|
||||||
uri := ctx.RequestURI()
|
uri := ctx.RequestURI()
|
||||||
|
|
||||||
|
|
|
@ -116,13 +116,13 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
|
||||||
r.GET("/"+f, handlerPublicHTML)
|
r.GET("/"+f, handlerPublicHTML)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.GET("/favicon.ico", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 0, handlerPublicHTML))
|
r.GET("/favicon.ico", middlewares.AssetOverride(config.Server.AssetPath, 0, handlerPublicHTML))
|
||||||
r.GET("/static/media/logo.png", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 2, handlerPublicHTML))
|
r.GET("/static/media/logo.png", middlewares.AssetOverride(config.Server.AssetPath, 2, handlerPublicHTML))
|
||||||
r.GET("/static/{filepath:*}", handlerPublicHTML)
|
r.GET("/static/{filepath:*}", handlerPublicHTML)
|
||||||
|
|
||||||
// Locales.
|
// Locales.
|
||||||
r.GET("/locales/{language:[a-z]{1,3}}-{variant:[a-zA-Z0-9-]+}/{namespace:[a-z]+}.json", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 0, handlerLocales))
|
r.GET("/locales/{language:[a-z]{1,3}}-{variant:[a-zA-Z0-9-]+}/{namespace:[a-z]+}.json", middlewares.AssetOverride(config.Server.AssetPath, 0, handlerLocales))
|
||||||
r.GET("/locales/{language:[a-z]{1,3}}/{namespace:[a-z]+}.json", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 0, handlerLocales))
|
r.GET("/locales/{language:[a-z]{1,3}}/{namespace:[a-z]+}.json", middlewares.AssetOverride(config.Server.AssetPath, 0, handlerLocales))
|
||||||
|
|
||||||
// Swagger.
|
// Swagger.
|
||||||
r.GET("/api/", middleware(serveSwaggerHandler))
|
r.GET("/api/", middleware(serveSwaggerHandler))
|
||||||
|
@ -298,9 +298,9 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
|
||||||
r.HandleMethodNotAllowed = true
|
r.HandleMethodNotAllowed = true
|
||||||
r.MethodNotAllowed = handlerMethodNotAllowed
|
r.MethodNotAllowed = handlerMethodNotAllowed
|
||||||
|
|
||||||
handler := middlewares.LogRequestMiddleware(r.Handler)
|
handler := middlewares.LogRequest(middlewares.SecurityHeaders(r.Handler))
|
||||||
if config.Server.Path != "" {
|
if config.Server.Path != "" {
|
||||||
handler = middlewares.StripPathMiddleware(config.Server.Path, handler)
|
handler = middlewares.StripPath(config.Server.Path, handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
return handler
|
return handler
|
||||||
|
|
Loading…
Reference in New Issue