1
0
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:
Vishal Rana 2016-05-03 08:32:28 -07:00
parent 392028c8af
commit 6424d779dc
6 changed files with 130 additions and 63 deletions

View File

@ -153,6 +153,7 @@ const (
HeaderUpgrade = "Upgrade"
HeaderVary = "Vary"
HeaderWWWAuthenticate = "WWW-Authenticate"
HeaderXForwardedProto = "X-Forwarded-Proto"
HeaderXHTTPMethodOverride = "X-HTTP-Method-Override"
HeaderXForwardedFor = "X-Forwarded-For"
HeaderXRealIP = "X-Real-IP"

View File

@ -76,8 +76,8 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
req := c.Request()
origin := c.Request().Header().Get(echo.HeaderOrigin)
header := c.Response().Header()
res := c.Response()
origin := req.Header().Get(echo.HeaderOrigin)
// Check allowed origins
allowedOrigin := ""
@ -90,42 +90,42 @@ func CORSWithConfig(config CORSConfig) echo.MiddlewareFunc {
// Simple request
if req.Method() != echo.OPTIONS {
header.Add(echo.HeaderVary, echo.HeaderOrigin)
res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
if origin == "" || allowedOrigin == "" {
return next(c)
}
header.Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
if config.AllowCredentials {
header.Set(echo.HeaderAccessControlAllowCredentials, "true")
res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
}
if exposeHeaders != "" {
header.Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
res.Header().Set(echo.HeaderAccessControlExposeHeaders, exposeHeaders)
}
return next(c)
}
// Preflight request
header.Add(echo.HeaderVary, echo.HeaderOrigin)
header.Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
header.Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
res.Header().Add(echo.HeaderVary, echo.HeaderOrigin)
res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestMethod)
res.Header().Add(echo.HeaderVary, echo.HeaderAccessControlRequestHeaders)
if origin == "" || allowedOrigin == "" {
return next(c)
}
header.Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
header.Set(echo.HeaderAccessControlAllowMethods, allowMethods)
res.Header().Set(echo.HeaderAccessControlAllowOrigin, allowedOrigin)
res.Header().Set(echo.HeaderAccessControlAllowMethods, allowMethods)
if config.AllowCredentials {
header.Set(echo.HeaderAccessControlAllowCredentials, "true")
res.Header().Set(echo.HeaderAccessControlAllowCredentials, "true")
}
if allowHeaders != "" {
header.Set(echo.HeaderAccessControlAllowHeaders, allowHeaders)
res.Header().Set(echo.HeaderAccessControlAllowHeaders, allowHeaders)
} else {
h := req.Header().Get(echo.HeaderAccessControlRequestHeaders)
if h != "" {
header.Set(echo.HeaderAccessControlAllowHeaders, h)
res.Header().Set(echo.HeaderAccessControlAllowHeaders, h)
}
}
if config.MaxAge > 0 {
header.Set(echo.HeaderAccessControlMaxAge, maxAge)
res.Header().Set(echo.HeaderAccessControlMaxAge, maxAge)
}
return c.NoContent(http.StatusNoContent)
}

View File

@ -35,13 +35,18 @@ func MethodOverride() echo.MiddlewareFunc {
// MethodOverrideWithConfig returns a method override middleware from config.
// See `MethodOverride()`.
func MethodOverrideWithConfig(config MethodOverrideConfig) echo.MiddlewareFunc {
// Defaults
if config.Getter == nil {
config.Getter = DefaultMethodOverrideConfig.Getter
}
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
req := c.Request()
if req.Method() == echo.POST {
m := config.Getter(c)
if m != "" {
c.Request().SetMethod(m)
req.SetMethod(m)
}
}
return next(c)

View File

@ -14,7 +14,7 @@ func TestMethodOverride(t *testing.T) {
e := echo.New()
m := MethodOverride()
h := func(c echo.Context) error {
return c.String(http.StatusOK, "Okay")
return c.String(http.StatusOK, "test")
}
// Override with http header

View File

@ -7,47 +7,95 @@ import (
)
type (
// SecureConfig defines the config for secure middleware.
SecureConfig struct {
DisableXSSProtection bool
DisableContentTypeNosniff bool
// XSSProtection provides protection against cross-site scripting attack (XSS)
// 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
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
// 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
}
)
var (
// DefaultSecureConfig is the default secure middleware config.
DefaultSecureConfig = SecureConfig{
XSSProtection: "1; mode=block",
ContentTypeNosniff: "nosniff",
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 {
return SecureWithConfig(DefaultSecureConfig)
}
// SecureWithConfig returns a secure middleware from config.
// See `Secure()`.
func SecureWithConfig(config SecureConfig) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
if !config.DisableXSSProtection {
c.Response().Header().Set(echo.HeaderXXSSProtection, "1; mode=block")
req := c.Request()
res := c.Response()
if config.XSSProtection != "" {
res.Header().Set(echo.HeaderXXSSProtection, config.XSSProtection)
}
if !config.DisableContentTypeNosniff {
c.Response().Header().Set(echo.HeaderXContentTypeOptions, "nosniff")
if config.ContentTypeNosniff != "" {
res.Header().Set(echo.HeaderXContentTypeOptions, config.ContentTypeNosniff)
}
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 := ""
if !config.DisableHSTSIncludeSubdomains {
if !config.HSTSExcludeSubdomains {
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 != "" {
c.Response().Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
res.Header().Set(echo.HeaderContentSecurityPolicy, config.ContentSecurityPolicy)
}
return next(c)
}

View File

@ -1,32 +1,45 @@
package middleware
// func TestSecureWithConfig(t *testing.T) {
// e := echo.New()
//
// config := SecureConfig{
// STSMaxAge: 100,
// STSIncludeSubdomains: true,
// FrameDeny: true,
// FrameOptionsValue: "",
// ContentTypeNosniff: true,
// XssProtected: true,
// XssProtectionValue: "",
// ContentSecurityPolicy: "default-src 'self'",
// DisableProdCheck: true,
// }
// secure := SecureWithConfig(config)
// h := secure(func(c echo.Context) error {
// return c.String(http.StatusOK, "test")
// })
//
// rq := test.NewRequest(echo.GET, "/", nil)
// rc := test.NewResponseRecorder()
// c := e.NewContext(rq, rc)
// h(c)
//
// assert.Equal(t, "max-age=100; includeSubdomains", rc.Header().Get(stsHeader))
// assert.Equal(t, "DENY", rc.Header().Get(frameOptionsHeader))
// assert.Equal(t, "nosniff", rc.Header().Get(contentTypeHeader))
// assert.Equal(t, xssProtectionValue, rc.Header().Get(xssProtectionHeader))
// assert.Equal(t, "default-src 'self'", rc.Header().Get(cspHeader))
// }
import (
"net/http"
"testing"
"github.com/labstack/echo"
"github.com/labstack/echo/test"
"github.com/stretchr/testify/assert"
)
func TestSecure(t *testing.T) {
e := echo.New()
req := test.NewRequest(echo.GET, "/", nil)
rec := test.NewResponseRecorder()
c := e.NewContext(req, rec)
h := func(c echo.Context) error {
return c.String(http.StatusOK, "test")
}
// Default
Secure()(h)(c)
assert.Equal(t, "1; mode=block", rec.Header().Get(echo.HeaderXXSSProtection))
assert.Equal(t, "nosniff", rec.Header().Get(echo.HeaderXContentTypeOptions))
assert.Equal(t, "SAMEORIGIN", rec.Header().Get(echo.HeaderXFrameOptions))
assert.Equal(t, "", rec.Header().Get(echo.HeaderStrictTransportSecurity))
assert.Equal(t, "", rec.Header().Get(echo.HeaderContentSecurityPolicy))
// Custom
req.Header().Set(echo.HeaderXForwardedProto, "https")
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))
}