secure

package module
v0.0.0-...-d9facd3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 17, 2018 License: MIT Imports: 3 Imported by: 0

README

About secure GoDoc Build Status

Package secure is an HTTP middleware for Go that handles adding security headers to HTTP responses, and accompanying security checks.

secure is a standard net/http.Handler, and can be used with Go's net/http package, or integrated with a number of frameworks.

Installation

Install in the standard Go way:

$ go get -u github.com/kenshaw/secure

Usage

Be sure to include an instance of the secure.Middleware as early as possible in your middleware chain, but added after any logging or recovery middleware. This allows the secure.Middleware to apply the defined security rules, and short-circuit any requests not satisfying the declared security policies.

The secure.Middleware can be used similarly to the following:

// examples/std/main.go
package main

import (
	"net/http"

	"github.com/kenshaw/secure"
)

var myHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello world"))
})

func main() {
	secureMiddleware := &secure.Middleware{
		AllowedHosts:             []string{"example.com", "ssl.example.com"},
		HostsProxyHeaders:        []string{"X-Forwarded-Host"},
		SSLRedirect:              true,
		SSLHost:                  "ssl.example.com",
		SSLForwardedProxyHeaders: map[string]string{"X-Forwarded-Proto": "https"},
		STSSeconds:               315360000,
		STSIncludeSubdomains:     true,
		STSPreload:               true,
		FrameDeny:                true,
		ContentTypeNosniff:       true,
		BrowserXSSFilter:         true,
		ContentSecurityPolicy:    "default-src 'self'",
	}

	app := secureMiddleware.Handler(myHandler)
	http.ListenAndServe("127.0.0.1:3000", app)
}

The above example allows requests with a host name of example.com, or ssl.example.com and will redirecte any HTTP requests to the HTTPS host ssl.example.com. Additionally, the above use of the secure.Middleware will add the following browser security headers after checking and applying the defined security policies:

Strict-Transport-Security: 315360000; includeSubdomains; preload
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Content-Security-Policy: default-src 'self'
Set the DevEnvironment option to true when developing!

When DevEnvironment is toggled, the AllowedHosts, SSLRedirect, and STS* header settings will be ignored and localhost will be permitted as an allowed host. This allows you to do development/testing without forced redirects to HTTPS (ie. allowing the developer to work on HTTP).

Configuration

secure comes with a variety of configuration options that can be set either directly on the secure.Middleware type, or by using the functional option pattern via a call to secure.New.

Please see the GoDoc listing for a full list of the API.

Redirecting HTTP to HTTPS

The following demonstrates redirecting all HTTP requests to HTTPS:

// examples/redirect/main.go
package main

import (
	"log"
	"net/http"

	"github.com/kenshaw/secure"
)

var myHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	w.Write([]byte("hello world"))
})

func main() {
	secureMiddleware := &secure.Middleware{
		SSLRedirect: true,

		// this is optional in production. the default behavior is to just
		// redirect the request to the https protocol. example:
		// http://github.com/some_page would be redirected to https://github.com/some_page
		SSLHost: "localhost:8443",
	}

	app := secureMiddleware.Handler(myHandler)

	// HTTP
	go func() {
		log.Fatal(http.ListenAndServe(":8080", app))
	}()

	// HTTPS
	// to generate a development cert and key, run the following from your *nix terminal:
	// go run $GOROOT/src/crypto/tls/generate_cert.go --host="localhost"
	log.Fatal(http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", app))
}
Strict Transport Security Headers

STS* headers will only be sent on verified HTTPS connections (and when DevEnvironment is not true).

Be sure to set the SSLForwardedProxyHeaders option if your application is behind a proxy to ensure the correct behavior. If you need STS* headers for all HTTP and HTTPS requests (which you SHOULD NOT), you may use the ForceSTSHeader option. Note that when DevEnvironment is true, it will disable this header, regardless if ForceSTSHeader is set to true.

NOTE: the preload flag is required for domain inclusion in Chrome's preload list.

Content Security Policy and WebSockets

If you need dynamic support for CSP when using WebSockets, please use this middleware instead.

Integration examples

The following are some examples of using secure.Middleware with common Go web frameworks and routers:

chi
// examples/chi/main.go
package main

import (
	"net/http"

	"github.com/kenshaw/secure"
	"github.com/pressly/chi"
)

func main() {
	secureMiddleware := &secure.Middleware{
		FrameDeny: true,
	}

	r := chi.NewRouter()

	r.Get("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("X-Frame-Options header is now `DENY`."))
	})
	r.Use(secureMiddleware.Handler)

	http.ListenAndServe("127.0.0.1:3000", r)
}
Echo
// examples/echo/main.go
package main

import (
	"net/http"

	"github.com/kenshaw/secure"
	"github.com/labstack/echo"
)

func main() {
	secureMiddleware := &secure.Middleware{
		FrameDeny: true,
	}

	e := echo.New()
	e.GET("/", func(c echo.Context) error {
		return c.String(http.StatusOK, "X-Frame-Options header is now `DENY`.")
	})

	e.Use(echo.WrapMiddleware(secureMiddleware.Handler))
	e.Logger.Fatal(e.Start("127.0.0.1:3000"))
}
Gin
// examples/gin/main.go
package main

import (
	"github.com/gin-gonic/gin"
	"github.com/kenshaw/secure"
)

func main() {
	secureMiddleware := &secure.Middleware{
		FrameDeny: true,
	}
	secureFunc := func() gin.HandlerFunc {
		return func(c *gin.Context) {
			err := secureMiddleware.Process(c.Writer, c.Request)

			// if there was an error, do not continue
			if err != nil {
				c.Abort()
				return
			}

			// avoid header rewrite if response is a redirection
			if status := c.Writer.Status(); status > 300 && status < 399 {
				c.Abort()
			}
		}
	}()

	router := gin.Default()
	router.Use(secureFunc)

	router.GET("/", func(c *gin.Context) {
		c.String(200, "X-Frame-Options header is now `DENY`.")
	})

	router.Run("127.0.0.1:3000")
}
Goji
// examples/goji/main.go
package main

import (
	"net/http"

	"github.com/kenshaw/secure"
	"goji.io"
	"goji.io/pat"
)

func main() {
	mux := goji.NewMux()
	mux.Use(secure.New(
		secure.FrameDeny(true),
	).Handler)

	mux.HandleFunc(pat.Get("/"), func(w http.ResponseWriter, req *http.Request) {
		w.Write([]byte("X-Frame-Options header is now `DENY`."))
	})

	http.ListenAndServe(":8080", mux)
}
Iris
// examples/iris/main.go
package main

import (
	"github.com/kataras/iris"
	"github.com/kenshaw/secure"
)

func main() {
	secureMiddleware := &secure.Middleware{
		FrameDeny: true,
	}

	app := iris.New()
	app.Use(func(c iris.Context) {
		err := secureMiddleware.Process(c.ResponseWriter(), c.Request())

		// if there was an error, do not continue
		if err != nil {
			return
		}

		c.Next()
	})

	app.Get("/home", func(c iris.Context) {
		c.StatusCode(200)
		c.WriteString("X-Frame-Options header is now `DENY`.")
	})

	app.Run(iris.Addr(":8080"))
}
Negroni

Note that the secure.Middleware type has a special helper function HandlerFuncWithNext for use with Negroni.

// examples/negroni/main.go
package main

import (
	"net/http"

	"github.com/codegangsta/negroni"
	"github.com/kenshaw/secure"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
		w.Write([]byte("X-Frame-Options header is now `DENY`."))
	})

	secureMiddleware := &secure.Middleware{
		FrameDeny: true,
	}

	n := negroni.Classic()
	n.Use(negroni.HandlerFunc(secureMiddleware.HandlerFuncWithNext))
	n.UseHandler(mux)

	n.Run("127.0.0.1:3000")
}

nginx

If you'd prefer to add the above security rules directly to your nginx configuration, please refer to the following:

# allowed hosts
if ($host !`* ^(example.com|ssl.example.com)$ ) {
    return 500;
}

# ssl redirect:
server {
    listen      80;
    server_name example.com ssl.example.com;
    return 301 https://ssl.example.com$request_uri;
}

# security headers
add_header Strict-Transport-Security "max-age=315360000";
add_header X-Frame-Options "DENY";
add_header X-Content-Type-Options "nosniff";
add_header X-XSS-Protection "1; mode=block";
add_header Content-Security-Policy "default-src 'self'";

Documentation

Overview

Package secure is an HTTP middleware for Go that handles adding security headers to HTTP responses, and accompanying security checks.

package main

import (
    "net/http"

    "github.com/kenshaw/secure"
)

var myHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte("hello world"))
})

func main() {
    secureMiddleware := secure.New(
        secure.AllowedHosts("www.example.com", "sub.example.com"),
        secure.SSLRedirect(true),
    })

    app := secureMiddleware.Handler(myHandler)
    http.ListenAndServe("127.0.0.1:3000", app)
}

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultBadHostHandler

func DefaultBadHostHandler(w http.ResponseWriter, r *http.Request)

DefaultBadHostHandler is the default bad host http handler.

Types

type Error

type Error string

Error is a secure error.

const (
	// ErrBadHost is the bad host error.
	ErrBadHost Error = "bad host"

	// ErrHTTPSRedirect is the https redirect error.
	ErrHTTPSRedirect Error = "https redirect"
)

Error values.

func (Error) Error

func (err Error) Error() string

Error satisfies the error interface.

type Middleware

type Middleware struct {
	// AllowedHosts is a list of fully qualified domain names that are allowed.
	// When empty, allows any host.
	AllowedHosts []string

	// HostsProxyHeaders is a set of header keys that may hold a proxied
	// hostname value for the request.
	HostsProxyHeaders []string

	// If SSLRedirect is set to true, then only allow https requests.
	SSLRedirect bool

	// If SSLTemporaryRedirect is true, the a 302 will be used while
	// redirecting.
	SSLTemporaryRedirect bool

	// SSLHost is the host name that is used to redirect http requests to
	// https. If not set, indicates to use the same host.
	SSLHost string

	// SSLForwardedProxyHeaders is the set of header keys with associated
	// values that would indicate a valid https request. This is used when
	// proxying requests from behind another webserver (ie, nginx, apache,
	// etc).
	//
	//     &secure.Middleware{
	//         SSLForwardedProxyHeaders: map[string]string{
	//             "X-Forwarded-Proto": "https",
	//         },
	//     }
	//
	SSLForwardedProxyHeaders map[string]string

	// STSSeconds is the max-age of the Strict-Transport-Security header.
	// Header will not be included if STSSeconds = 0.
	STSSeconds int64

	// When STSIncludeSubdomains is true, `includeSubdomains` will be appended to
	// the Strict-Transport-Security header.
	STSIncludeSubdomains bool

	// When STSPreload is true, the `preload` flag will be appended to the
	// Strict-Transport-Security header.
	STSPreload bool

	// When ForceSTSHeader is true, the STS header will be added even when the
	// connection is HTTP.
	ForceSTSHeader bool

	// When FrameDeny is true, adds the X-Frame-Options header with the value
	// of `DENY`.
	FrameDeny bool

	// CustomFrameOptionsValue allows the X-Frame-Options header value to be
	// set with a custom value. Overrides the FrameDeny option.
	CustomFrameOptionsValue string

	// If ContentTypeNosniff is true, adds the X-Content-Type-Options header
	// with the value `nosniff`.
	ContentTypeNosniff bool

	// If BrowserXSSFilter is true, adds the X-XSS-Protection header with the
	// value `1; mode=block`.
	BrowserXSSFilter bool

	// CustomBrowserXSSValue allows the X-XSS-Protection header value to be set
	// with a custom value. This overrides the BrowserXSSFilter option.
	CustomBrowserXSSValue string

	// ContentSecurityPolicy allows the Content-Security-Policy header value to
	// be set with a custom value.
	ContentSecurityPolicy string

	// ReferrerPolicy configures which the browser referrer policy.
	ReferrerPolicy string

	// BadHostHandler is the bad host handler.
	BadHostHandler http.HandlerFunc

	// When DevEnvironment is true, disables the AllowedHosts, SSL, and STS
	// checks.
	//
	// This should be toggled only when testing / developing, and is necessary
	// when testing sites configured only for https from a http based
	// connection.
	//
	// If you would like your development environment to mimic production with
	// complete Host blocking, SSL redirects, and STS headers, leave this as
	// false.
	DevEnvironment bool
}

Middleware that sets basic security headers and provides simple security checks for http servers.

func New

func New(opts ...Option) *Middleware

New constructs a new secure Middleware instance with the supplied options.

func (*Middleware) Handler

func (s *Middleware) Handler(h http.Handler) http.Handler

Handler implements the http.HandlerFunc for integration with the standard net/http lib.

func (*Middleware) HandlerFuncWithNext

func (s *Middleware) HandlerFuncWithNext(w http.ResponseWriter, r *http.Request, next http.HandlerFunc)

HandlerFuncWithNext is a special implementation for Negroni, but could be used elsewhere.

func (*Middleware) Process

func (s *Middleware) Process(w http.ResponseWriter, r *http.Request) error

Process runs the actual checks and returns an error if the middleware chain should stop.

type Option

type Option func(*Middleware)

Option is a secure Middleware option.

func AllowedHosts

func AllowedHosts(allowedHosts ...string) Option

AllowedHosts is an option to set the allowed hosts.

func BadHostHandler

func BadHostHandler(badHostHandler http.HandlerFunc) Option

BadHostHandler is an option to set the bad host handler.

func BrowserXSSFilter

func BrowserXSSFilter(browserXSSFilter bool) Option

BrowserXSSFilter is an option to set browser xss filter.

func ContentSecurityPolicy

func ContentSecurityPolicy(contentSecurityPolicy string) Option

ContentSecurityPolicy is an option to set the content security policy.

func ContentTypeNosniff

func ContentTypeNosniff(contentTypeNosniff bool) Option

ContentTypeNosniff is an option to set content type to NOSNIFF.

func CustomBrowserXSSValue

func CustomBrowserXSSValue(customBrowserXSSValue string) Option

CustomBrowserXSSValue is an option to set custom browser xss value.

func CustomFrameOptionsValue

func CustomFrameOptionsValue(customFrameOptionsValue string) Option

CustomFrameOptionsValue is an option to set custom frame options value.

func DevEnvironment

func DevEnvironment(isDevEnvironment bool) Option

DevEnvironment is an option to set toggle development environment options.

func ForceSTSHeader

func ForceSTSHeader(forceSTSHeader bool) Option

ForceSTSHeader is an option to force STS header.

func FrameDeny

func FrameDeny(frameDeny bool) Option

FrameDeny is an option to set frame deny.

func HostsProxyHeaders

func HostsProxyHeaders(hostsProxyHeaders ...string) Option

HostsProxyHeaders is an option to set the host proxy headers.

func ReferrerPolicy

func ReferrerPolicy(referrerPolicy string) Option

ReferrerPolicy is an option to set the referrer policy.

func SSLForwardedProxyHeaders

func SSLForwardedProxyHeaders(m map[string]string) Option

SSLForwardedProxyHeaders is an option to set the SSL forwarded proxy headers.

func SSLHost

func SSLHost(sslHost string) Option

SSLHost is an option to set the ssl host.

func SSLRedirect

func SSLRedirect(sslRedirect bool) Option

SSLRedirect is an option to toggle ssl redirect.

func SSLTemporaryRedirect

func SSLTemporaryRedirect(sslTemporaryRedirect bool) Option

SSLTemporaryRedirect is an option to set the SSL temporary redirect.

func STSIncludeSubdomains

func STSIncludeSubdomains(stsIncludeSubdomains bool) Option

STSIncludeSubdomains is an option to set STS include subdomains.

func STSPreload

func STSPreload(stsPreload bool) Option

STSPreload is an option to set STS preload.

func STSSeconds

func STSSeconds(stsSeconds int64) Option

STSSeconds is an option to set the STS seconds.

Directories

Path Synopsis
_examples
chi
examples/chi/main.go
examples/chi/main.go
echo
examples/echo/main.go
examples/echo/main.go
gin
examples/gin/main.go
examples/gin/main.go
goji
examples/goji/main.go
examples/goji/main.go
iris
examples/iris/main.go
examples/iris/main.go
negroni
examples/negroni/main.go
examples/negroni/main.go
redirect
examples/redirect/main.go
examples/redirect/main.go
std
examples/std/main.go
examples/std/main.go

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL