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
James Elliott 2022-05-03 12:19:30 +10:00 committed by GitHub
parent 7f0e758188
commit 556a115c83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 37 additions and 13 deletions

View File

@ -7,8 +7,8 @@ import (
"github.com/valyala/fasthttp"
)
// AssetOverrideMiddleware allows overriding and serving of specific embedded assets from disk.
func AssetOverrideMiddleware(root string, strip int, next fasthttp.RequestHandler) fasthttp.RequestHandler {
// AssetOverride allows overriding and serving of specific embedded assets from disk.
func AssetOverride(root string, strip int, next fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
if root == "" {
next(ctx)

View File

@ -30,6 +30,10 @@ var (
headerAccessControlMaxAge = []byte(fasthttp.HeaderAccessControlMaxAge)
headerAccessControlRequestHeaders = []byte(fasthttp.HeaderAccessControlRequestHeaders)
headerAccessControlRequestMethod = []byte(fasthttp.HeaderAccessControlRequestMethod)
headerXContentTypeOptions = []byte(fasthttp.HeaderXContentTypeOptions)
headerReferrerPolicy = []byte(fasthttp.HeaderReferrerPolicy)
headerPermissionsPolicy = []byte("Permissions-Policy")
)
var (
@ -40,6 +44,10 @@ var (
headerValueVaryWildcard = []byte("Accept-Encoding")
headerValueOriginWildcard = []byte("*")
headerValueZero = []byte("0")
headerValueNoSniff = []byte("nosniff")
headerValueStrictOriginCrossOrigin = []byte("strict-origin-when-cross-origin")
headerValueCohort = []byte("interest-cohort=()")
)
var (

View File

@ -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)
}
}

View File

@ -4,8 +4,8 @@ import (
"github.com/valyala/fasthttp"
)
// LogRequestMiddleware logs the query that is being treated.
func LogRequestMiddleware(next fasthttp.RequestHandler) fasthttp.RequestHandler {
// LogRequest logs the query that is being treated.
func LogRequest(next fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
autheliaCtx := &AutheliaCtx{RequestCtx: ctx}
logger := NewRequestLogger(autheliaCtx)

View File

@ -13,7 +13,7 @@ func TestShouldCallNextFunction(t *testing.T) {
f := func(ctx *fasthttp.RequestCtx) { val = true }
context := &fasthttp.RequestCtx{}
LogRequestMiddleware(f)(context)
LogRequest(f)(context)
assert.Equal(t, true, val)
}

View File

@ -6,8 +6,8 @@ import (
"github.com/valyala/fasthttp"
)
// StripPathMiddleware strips the first level of a path.
func StripPathMiddleware(path string, next fasthttp.RequestHandler) fasthttp.RequestHandler {
// StripPath strips the first level of a path.
func StripPath(path string, next fasthttp.RequestHandler) fasthttp.RequestHandler {
return func(ctx *fasthttp.RequestCtx) {
uri := ctx.RequestURI()

View File

@ -116,13 +116,13 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
r.GET("/"+f, handlerPublicHTML)
}
r.GET("/favicon.ico", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 0, handlerPublicHTML))
r.GET("/static/media/logo.png", middlewares.AssetOverrideMiddleware(config.Server.AssetPath, 2, handlerPublicHTML))
r.GET("/favicon.ico", middlewares.AssetOverride(config.Server.AssetPath, 0, handlerPublicHTML))
r.GET("/static/media/logo.png", middlewares.AssetOverride(config.Server.AssetPath, 2, handlerPublicHTML))
r.GET("/static/{filepath:*}", handlerPublicHTML)
// 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}}/{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.AssetOverride(config.Server.AssetPath, 0, handlerLocales))
// Swagger.
r.GET("/api/", middleware(serveSwaggerHandler))
@ -298,9 +298,9 @@ func getHandler(config schema.Configuration, providers middlewares.Providers) fa
r.HandleMethodNotAllowed = true
r.MethodNotAllowed = handlerMethodNotAllowed
handler := middlewares.LogRequestMiddleware(r.Handler)
handler := middlewares.LogRequest(middlewares.SecurityHeaders(r.Handler))
if config.Server.Path != "" {
handler = middlewares.StripPathMiddleware(config.Server.Path, handler)
handler = middlewares.StripPath(config.Server.Path, handler)
}
return handler