mirror of
https://github.com/labstack/echo.git
synced 2025-01-12 01:22:21 +02:00
Added test for secure middleware
Signed-off-by: Vishal Rana <vr@labstack.com>
This commit is contained in:
parent
392028c8af
commit
6424d779dc
1
echo.go
1
echo.go
@ -153,6 +153,7 @@ const (
|
|||||||
HeaderUpgrade = "Upgrade"
|
HeaderUpgrade = "Upgrade"
|
||||||
HeaderVary = "Vary"
|
HeaderVary = "Vary"
|
||||||
HeaderWWWAuthenticate = "WWW-Authenticate"
|
HeaderWWWAuthenticate = "WWW-Authenticate"
|
||||||
|
HeaderXForwardedProto = "X-Forwarded-Proto"
|
||||||
HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
|
HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
|
||||||
HeaderXForwardedFor = "X-Forwarded-For"
|
HeaderXForwardedFor = "X-Forwarded-For"
|
||||||
HeaderXRealIP = "X-Real-IP"
|
HeaderXRealIP = "X-Real-IP"
|
||||||
|
@ -76,8 +76,8 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
|||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
req := c.Request()
|
req := c.Request()
|
||||||
origin := c.Request().Header().Get(echo.HeaderOrigin)
|
res := c.Response()
|
||||||
header := c.Response().Header()
|
origin := req.Header().Get(echo.HeaderOrigin)
|
||||||
|
|
||||||
// Check allowed origins
|
// Check allowed origins
|
||||||
allowedOrigin := ""
|
allowedOrigin := ""
|
||||||
@ -90,42 +90,42 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
|
|||||||
|
|
||||||
// Simple request
|
// Simple request
|
||||||
if req.Method() != echo.OPTIONS {
|
if req.Method() != echo.OPTIONS {
|
||||||
header.Add(echo.HeaderVary, echo.HeaderOrigin)
|
res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
|
||||||
if origin == "" || allowedOrigin == "" {
|
if origin == "" || allowedOrigin == "" {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
header.Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
|
res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
|
||||||
if config.AllowCredentials {
|
if config.AllowCredentials {
|
||||||
header.Set(echo.HeaderAccessControlAllowCredentials, "true")
|
res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
|
||||||
}
|
}
|
||||||
if exposeHeaders != "" {
|
if exposeHeaders != "" {
|
||||||
header.Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
|
res.Header().Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
|
||||||
}
|
}
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preflight request
|
// Preflight request
|
||||||
header.Add(echo.HeaderVary, echo.HeaderOrigin)
|
res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
|
||||||
header.Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
|
res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
|
||||||
header.Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
|
res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
|
||||||
if origin == "" || allowedOrigin == "" {
|
if origin == "" || allowedOrigin == "" {
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
header.Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
|
res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
|
||||||
header.Set(echo.HeaderAccessControlAllowMethods, allowMethods)
|
res.Header().Set(echo.HeaderAccessControlAllowMethods, allowMethods)
|
||||||
if config.AllowCredentials {
|
if config.AllowCredentials {
|
||||||
header.Set(echo.HeaderAccessControlAllowCredentials, "true")
|
res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
|
||||||
}
|
}
|
||||||
if allowHeaders != "" {
|
if allowHeaders != "" {
|
||||||
header.Set(echo.HeaderAccessControlAllowHeaders, allowHeaders)
|
res.Header().Set(echo.HeaderAccessControlAllowHeaders, allowHeaders)
|
||||||
} else {
|
} else {
|
||||||
h := req.Header().Get(echo.HeaderAccessControlRequestHeaders)
|
h := req.Header().Get(echo.HeaderAccessControlRequestHeaders)
|
||||||
if h != "" {
|
if h != "" {
|
||||||
header.Set(echo.HeaderAccessControlAllowHeaders, h)
|
res.Header().Set(echo.HeaderAccessControlAllowHeaders, h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.MaxAge > 0 {
|
if config.MaxAge > 0 {
|
||||||
header.Set(echo.HeaderAccessControlMaxAge, maxAge)
|
res.Header().Set(echo.HeaderAccessControlMaxAge, maxAge)
|
||||||
}
|
}
|
||||||
return c.NoContent(http.StatusNoContent)
|
return c.NoContent(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
@ -35,13 +35,18 @@ func MethodOverride() echo.MiddlewareFunc {
|
|||||||
// MethodOverrideWithConfig returns a method override middleware from config.
|
// MethodOverrideWithConfig returns a method override middleware from config.
|
||||||
// See `MethodOverride()`.
|
// See `MethodOverride()`.
|
||||||
func MethodOverrideWithConfig(config MethodOverrideConfig) echo.MiddlewareFunc {
|
func MethodOverrideWithConfig(config MethodOverrideConfig) echo.MiddlewareFunc {
|
||||||
|
// Defaults
|
||||||
|
if config.Getter == nil {
|
||||||
|
config.Getter = DefaultMethodOverrideConfig.Getter
|
||||||
|
}
|
||||||
|
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
req := c.Request()
|
req := c.Request()
|
||||||
if req.Method() == echo.POST {
|
if req.Method() == echo.POST {
|
||||||
m := config.Getter(c)
|
m := config.Getter(c)
|
||||||
if m != "" {
|
if m != "" {
|
||||||
c.Request().SetMethod(m)
|
req.SetMethod(m)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return next(c)
|
return next(c)
|
||||||
|
@ -14,7 +14,7 @@ func TestMethodOverride(t *testing.T) {
|
|||||||
e := echo.New()
|
e := echo.New()
|
||||||
m := MethodOverride()
|
m := MethodOverride()
|
||||||
h := func(c echo.Context) error {
|
h := func(c echo.Context) error {
|
||||||
return c.String(http.StatusOK, "Okay")
|
return c.String(http.StatusOK, "test")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override with http header
|
// Override with http header
|
||||||
|
@ -7,47 +7,95 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
// SecureConfig defines the config for secure middleware.
|
||||||
SecureConfig struct {
|
SecureConfig struct {
|
||||||
DisableXSSProtection bool
|
// XSSProtection provides protection against cross-site scripting attack (XSS)
|
||||||
DisableContentTypeNosniff bool
|
// by setting the `X-XSS-Protection` header.
|
||||||
|
// Optional, with default value as `1; mode=block`.
|
||||||
|
XSSProtection string
|
||||||
|
|
||||||
|
// ContentTypeNosniff provides protection against overriding Content-Type
|
||||||
|
// header by setting the `X-Content-Type-Options` header.
|
||||||
|
// Optional, with default value as "nosniff".
|
||||||
|
ContentTypeNosniff string
|
||||||
|
|
||||||
|
// XFrameOptions can be used to indicate whether or not a browser should
|
||||||
|
// be allowed to render a page in a <frame>, <iframe> or <object> .
|
||||||
|
// Sites can use this to avoid clickjacking attacks, by ensuring that their
|
||||||
|
// content is not embedded into other sites.provides protection against
|
||||||
|
// clickjacking.
|
||||||
|
// Optional, with default value as "SAMEORIGIN".
|
||||||
|
// Possible values:
|
||||||
|
// `SAMEORIGIN` - The page can only be displayed in a frame on the same origin as the page itself.
|
||||||
|
// `DENY` - The page cannot be displayed in a frame, regardless of the site attempting to do so.
|
||||||
|
// `ALLOW-FROM uri` - The page can only be displayed in a frame on the specified origin.
|
||||||
XFrameOptions string
|
XFrameOptions string
|
||||||
DisableHSTSIncludeSubdomains bool
|
|
||||||
|
// HSTSMaxAge sets the `Strict-Transport-Security` header to indicate how
|
||||||
|
// long (in seconds) browsers should remember that this site is only to
|
||||||
|
// be accessed using HTTPS. This reduces your exposure to some SSL-stripping
|
||||||
|
// man-in-the-middle (MITM) attacks.
|
||||||
|
// Optional, with default value as 0.
|
||||||
HSTSMaxAge int
|
HSTSMaxAge int
|
||||||
|
|
||||||
|
// HSTSExcludeSubdomains won't include subdomains tag in the `Strict Transport Security`
|
||||||
|
// header, excluding all subdomains from security policy. It has no effect
|
||||||
|
// unless HSTSMaxAge is set to a non-zero value.
|
||||||
|
// Optional, with default value as false.
|
||||||
|
HSTSExcludeSubdomains bool
|
||||||
|
|
||||||
|
// ContentSecurityPolicy sets the `Content-Security-Policy` header providing
|
||||||
|
// security against cross-site scripting (XSS), clickjacking and other code
|
||||||
|
// injection attacks resulting from execution of malicious content in the
|
||||||
|
// trusted web page context.
|
||||||
|
// Optional, with default value as "".
|
||||||
ContentSecurityPolicy string
|
ContentSecurityPolicy string
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
// DefaultSecureConfig is the default secure middleware config.
|
||||||
DefaultSecureConfig = SecureConfig{
|
DefaultSecureConfig = SecureConfig{
|
||||||
|
XSSProtection: "1; mode=block",
|
||||||
|
ContentTypeNosniff: "nosniff",
|
||||||
XFrameOptions: "SAMEORIGIN",
|
XFrameOptions: "SAMEORIGIN",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Secure returns a secure middleware.
|
||||||
|
// Secure middleware provide protection against cross-site scripting (XSS) attack,
|
||||||
|
// content type sniffing, clickjacking, insecure connection and other code
|
||||||
|
// injection attacks.
|
||||||
func Secure() echo.MiddlewareFunc {
|
func Secure() echo.MiddlewareFunc {
|
||||||
return SecureWithConfig(DefaultSecureConfig)
|
return SecureWithConfig(DefaultSecureConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SecureWithConfig returns a secure middleware from config.
|
||||||
|
// See `Secure()`.
|
||||||
func SecureWithConfig(config SecureConfig) echo.MiddlewareFunc {
|
func SecureWithConfig(config SecureConfig) echo.MiddlewareFunc {
|
||||||
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
return func(next echo.HandlerFunc) echo.HandlerFunc {
|
||||||
return func(c echo.Context) error {
|
return func(c echo.Context) error {
|
||||||
if !config.DisableXSSProtection {
|
req := c.Request()
|
||||||
c.Response().Header().Set(echo.HeaderXXSSProtection, "1; mode=block")
|
res := c.Response()
|
||||||
|
|
||||||
|
if config.XSSProtection != "" {
|
||||||
|
res.Header().Set(echo.HeaderXXSSProtection, config.XSSProtection)
|
||||||
}
|
}
|
||||||
if !config.DisableContentTypeNosniff {
|
if config.ContentTypeNosniff != "" {
|
||||||
c.Response().Header().Set(echo.HeaderXContentTypeOptions, "nosniff")
|
res.Header().Set(echo.HeaderXContentTypeOptions, config.ContentTypeNosniff)
|
||||||
}
|
}
|
||||||
if config.XFrameOptions != "" {
|
if config.XFrameOptions != "" {
|
||||||
c.Response().Header().Set(echo.HeaderXFrameOptions, config.XFrameOptions)
|
res.Header().Set(echo.HeaderXFrameOptions, config.XFrameOptions)
|
||||||
}
|
}
|
||||||
if config.HSTSMaxAge != 0 {
|
if (req.IsTLS() || (req.Header().Get(echo.HeaderXForwardedProto) == "https")) && config.HSTSMaxAge != 0 {
|
||||||
subdomains := ""
|
subdomains := ""
|
||||||
if !config.DisableHSTSIncludeSubdomains {
|
if !config.HSTSExcludeSubdomains {
|
||||||
subdomains = "; includeSubdomains"
|
subdomains = "; includeSubdomains"
|
||||||
}
|
}
|
||||||
c.Response().Header().Set(echo.HeaderStrictTransportSecurity, fmt.Sprintf("max-age=%d%s", config.HSTSMaxAge, subdomains))
|
res.Header().Set(echo.HeaderStrictTransportSecurity, fmt.Sprintf("max-age=%d%s", config.HSTSMaxAge, subdomains))
|
||||||
}
|
}
|
||||||
if config.ContentSecurityPolicy != "" {
|
if config.ContentSecurityPolicy != "" {
|
||||||
c.Response().Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
|
res.Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
|
||||||
}
|
}
|
||||||
return next(c)
|
return next(c)
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,45 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
// func TestSecureWithConfig(t *testing.T) {
|
import (
|
||||||
// e := echo.New()
|
"net/http"
|
||||||
//
|
"testing"
|
||||||
// config := SecureConfig{
|
|
||||||
// STSMaxAge: 100,
|
"github.com/labstack/echo"
|
||||||
// STSIncludeSubdomains: true,
|
"github.com/labstack/echo/test"
|
||||||
// FrameDeny: true,
|
"github.com/stretchr/testify/assert"
|
||||||
// FrameOptionsValue: "",
|
)
|
||||||
// ContentTypeNosniff: true,
|
|
||||||
// XssProtected: true,
|
func TestSecure(t *testing.T) {
|
||||||
// XssProtectionValue: "",
|
e := echo.New()
|
||||||
// ContentSecurityPolicy: "default-src 'self'",
|
req := test.NewRequest(echo.GET, "/", nil)
|
||||||
// DisableProdCheck: true,
|
rec := test.NewResponseRecorder()
|
||||||
// }
|
c := e.NewContext(req, rec)
|
||||||
// secure := SecureWithConfig(config)
|
h := func(c echo.Context) error {
|
||||||
// h := secure(func(c echo.Context) error {
|
return c.String(http.StatusOK, "test")
|
||||||
// return c.String(http.StatusOK, "test")
|
}
|
||||||
// })
|
|
||||||
//
|
// Default
|
||||||
// rq := test.NewRequest(echo.GET, "/", nil)
|
Secure()(h)(c)
|
||||||
// rc := test.NewResponseRecorder()
|
assert.Equal(t, "1; mode=block", rec.Header().Get(echo.HeaderXXSSProtection))
|
||||||
// c := e.NewContext(rq, rc)
|
assert.Equal(t, "nosniff", rec.Header().Get(echo.HeaderXContentTypeOptions))
|
||||||
// h(c)
|
assert.Equal(t, "SAMEORIGIN", rec.Header().Get(echo.HeaderXFrameOptions))
|
||||||
//
|
assert.Equal(t, "", rec.Header().Get(echo.HeaderStrictTransportSecurity))
|
||||||
// assert.Equal(t, "max-age=100; includeSubdomains", rc.Header().Get(stsHeader))
|
assert.Equal(t, "", rec.Header().Get(echo.HeaderContentSecurityPolicy))
|
||||||
// assert.Equal(t, "DENY", rc.Header().Get(frameOptionsHeader))
|
|
||||||
// assert.Equal(t, "nosniff", rc.Header().Get(contentTypeHeader))
|
// Custom
|
||||||
// assert.Equal(t, xssProtectionValue, rc.Header().Get(xssProtectionHeader))
|
req.Header().Set(echo.HeaderXForwardedProto, "https")
|
||||||
// assert.Equal(t, "default-src 'self'", rc.Header().Get(cspHeader))
|
rec = test.NewResponseRecorder()
|
||||||
// }
|
c = e.NewContext(req, rec)
|
||||||
|
SecureWithConfig(SecureConfig{
|
||||||
|
XSSProtection: "",
|
||||||
|
ContentTypeNosniff: "",
|
||||||
|
XFrameOptions: "",
|
||||||
|
HSTSMaxAge: 3600,
|
||||||
|
ContentSecurityPolicy: "default-src 'self'",
|
||||||
|
})(h)(c)
|
||||||
|
assert.Equal(t, "", rec.Header().Get(echo.HeaderXXSSProtection))
|
||||||
|
assert.Equal(t, "", rec.Header().Get(echo.HeaderXContentTypeOptions))
|
||||||
|
assert.Equal(t, "", rec.Header().Get(echo.HeaderXFrameOptions))
|
||||||
|
assert.Equal(t, "max-age=3600; includeSubdomains", rec.Header().Get(echo.HeaderStrictTransportSecurity))
|
||||||
|
assert.Equal(t, "default-src 'self'", rec.Header().Get(echo.HeaderContentSecurityPolicy))
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user