umbrella

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Aug 1, 2020 License: MIT Imports: 10 Imported by: 0

README

umbrella

test codecov go.dev reference go report card license

This package provides middleware intended for use with various frameworks compatible with the standard net/http ecosystem.

Installation

go get -u github.com/kenkyu392/umbrella

Middlewares

Middleware Description
Use Creates a single middleware that executes multiple middlewares.
RealIP Override the RemoteAddr in http.Request with an X-Forwarded-For or X-Real-IP header.
Recover Recover from panic and record a stack trace and return a 500 Internal Server Error status.
Timeout Timeout cancels the context at the given time.
Context Context is middleware that operates the context of request scope.
HSTS HSTS adds the Strict-Transport-Security header.
Clickjacking Clickjacking mitigates clickjacking attacks by limiting the display of iframe.
ContentSniffing ContentSniffing adds a header for Content-Type sniffing vulnerability countermeasures.
CacheControl/NoCache CacheControl/NoCache adds the Cache-Control header.
AllowUserAgent/DisallowUserAgent Allow/DisallowUserAgent is middleware that performs authentication based on the request User-Agent.
AllowContentType/DisallowContentType Allow/DisallowContentType is middleware that performs authentication based on the request Content-Type.
AllowMethod/DisallowMethod Create an access control using the request method.
RequestHeader/ResponseHeader Request/ResponseHeader is middleware that edits request and response headers.
Use

Creates a single middleware that executes multiple middlewares.

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		for k := range w.Header() {
			fmt.Fprintf(w, "%s: %s\n", k, w.Header().Get(k))
		}
	})

	m := http.NewServeMux()

	// Creates a single middleware that executes multiple middlewares.
	mw := umbrella.Use(
		umbrella.AllowUserAgent("Firefox", "Chrome"),
		umbrella.Clickjacking("deny"),
		umbrella.ContentSniffing(),
		umbrella.NoCache(),
		umbrella.Timeout(time.Millisecond*800),
	)
	m.Handle("/", mw(handler))

	http.ListenAndServe(":3000", m)
}
RealIP

Override the RemoteAddr in http.Request with an X-Forwarded-For or X-Real-IP header.

package main

import (
	"fmt"
	"net/http"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		// If an X-Forwarded-For or X-Real-IP header is received,
		// RemoteAddr will be overwritten.
		fmt.Fprintf(w, "RemoteAddr: %v\n", r.RemoteAddr)
		r.Write(w)
	})

	m := http.NewServeMux()

	mw := umbrella.RealIP()
	m.Handle("/", mw(handler))

	http.ListenAndServe(":3000", m)
}
Recover

Recover from panic and record a stack trace and return a 500 Internal Server Error status.

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		now := time.Now()
		if now.Unix()%2 == 0 {
			panic(fmt.Sprintf("panic: %v\n", now))
		}
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "Time: %v\n", now)
		r.Write(w)
	})

	m := http.NewServeMux()

	// If you give nil, it will be output to os.Stderr.
	mw := umbrella.Recover(nil)
	m.Handle("/", mw(handler))

	http.ListenAndServe(":3000", m)
}
Timeout

Timeout cancels the context at the given time.

package main

import (
	"fmt"
	"math/rand"
	"net/http"
	"time"

	"github.com/kenkyu392/umbrella"
)

func init() {
	rand.Seed(time.Now().UnixNano())
}

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		d := time.Millisecond * time.Duration(rand.Intn(500)+500)
		ctx := r.Context()
		select {
		case <-ctx.Done():
			return
		case <-time.After(d):
		}
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "duration: %v", d)
	})

	m := http.NewServeMux()

	// This handler times out in 800ms.
	mw := umbrella.Timeout(time.Millisecond * 800)
	m.Handle("/", mw(handler))

	http.ListenAndServe(":3000", m)
}
HSTS

HSTS adds the Strict-Transport-Security header.
Proper use of this header will mitigate stripping attacks.

package main

import (
	"fmt"
	"net/http"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w,
			"Strict-Transport-Security: %v",
			w.Header().Get("Strict-Transport-Security"),
		)
	})

	m := http.NewServeMux()

	// Tells the browser to use HTTPS instead of HTTP to connect to a domain
	// (including subdomains).
	mw := umbrella.HSTS(60, "includeSubDomains")
	m.Handle("/", mw(handler))

	http.ListenAndServe(":3000", m)
}
Clickjacking

Clickjacking mitigates clickjacking attacks by limiting the display of iframe.

package main

import (
	"net/http"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		// This iframe is not displayed.
		w.Write([]byte(`<iframe src="https://www.google.com/"></iframe>`))
	})

	m := http.NewServeMux()

	// Limit the display of iframe to mitigate clickjacking attacks.
	mw := umbrella.Clickjacking("deny")
	m.Handle("/", mw(handler))

	http.ListenAndServe(":3000", m)
}
ContentSniffing

ContentSniffing adds a header for Content-Type sniffing vulnerability countermeasures.

package main

import (
	"fmt"
	"net/http"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w,
			"X-Content-Type-Options: %v",
			w.Header().Get("X-Content-Type-Options"),
		)
	})

	m := http.NewServeMux()

	// It implements a countermeasure for Content-Type snuffing vulnerability,
	// which is a problem in old Internet Explorer, for example.
	mw := umbrella.ContentSniffing()
	m.Handle("/", mw(handler))

	http.ListenAndServe(":3000", m)
}
CacheControl/NoCache

CacheControl/NoCache adds the Cache-Control header.

package main

import (
	"crypto/md5"
	"fmt"
	"net/http"
	"strings"

	"github.com/kenkyu392/umbrella"
)

func main() {
	data := []byte(`<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg">
	<circle cx="50" cy="50" r="40" stroke="#6a737d" stroke-width="4" fill="#1b1f23" />
	</svg>`)
	etag := fmt.Sprintf(`"%x"`, md5.Sum(data))
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if match := r.Header.Get("If-None-Match"); strings.Contains(match, etag) {
			w.WriteHeader(http.StatusNotModified)
			return
		}
		w.Header().Set("Content-Type", "image/svg+xml")
		w.Header().Set("ETag", etag)
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(data))
	})

	m := http.NewServeMux()

	// Enable browser cache for 2 days.
	// mw := umbrella.NoCache()
	mw := umbrella.CacheControl("public", "max-age=172800", "s-maxage=172800")
	m.Handle("/", mw(handler))

	http.ListenAndServe(":3000", m)
}
Context

Context is middleware that operates the context of request scope.

package main

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/kenkyu392/umbrella"
)

type key struct{}

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "context: %v", r.Context().Value(key{}))
	})

	m := http.NewServeMux()

	// You can embed the value in the request context.
	mw := umbrella.Context(func(ctx context.Context) context.Context {
		return context.WithValue(ctx, key{}, time.Now().UnixNano())
	})
	m.Handle("/", mw(handler))

	http.ListenAndServe(":3000", m)
}
AllowUserAgent/DisallowUserAgent

Allow/DisallowUserAgent is middleware that performs authentication based on the request User-Agent.

package main

import (
	"fmt"
	"net/http"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "ua: %v", r.UserAgent())
	})

	m := http.NewServeMux()

  // Only accessible in Firefox and Chrome.
  allows := umbrella.AllowUserAgent("Firefox", "Chrome")
	m.Handle("/allows",
		allows(handler),
  )

  // Not accessible in Edge and Internet Explorer.
  disallows := umbrella.DisallowUserAgent("Edg", "MSIE")
	m.Handle("/disallows",
		disallows(handler),
	)

	http.ListenAndServe(":3000", m)
}
AllowContentType/DisallowContentType

Allow/DisallowContentType is middleware that performs authentication based on the request Content-Type.

package main

import (
	"fmt"
	"net/http"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "ua: %v", r.UserAgent())
	})

	m := http.NewServeMux()

	allows := umbrella.AllowContentType(
		"application/json", "text/json",
		"application/xml", "text/xml",
	)
	disallows := umbrella.DisallowContentType(
		"text/plain", "application/octet-stream",
	)

	// Only accessible in JSON and XML.
	m.Handle("/allows",
		allows(handler),
	)
	// Not accessible in Plain text and Binary data.
	m.Handle("/disallows",
		disallows(handler),
	)

	http.ListenAndServe(":3000", m)
}
AllowMethod/DisallowMethod

Create an access control using the request method.

package main

import (
	"net/http"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		r.Write(w)
	})

	m := http.NewServeMux()

	// Create an access control using the request method.
	mw1 := umbrella.DisallowMethod(http.MethodGet)
	mw2 := umbrella.AllowMethod(http.MethodGet)
	m.Handle("/mw1", mw1(handler))
	m.Handle("/mw2", mw2(handler))

	http.ListenAndServe(":3000", m)
}
RequestHeader/ResponseHeader

Request/ResponseHeader is middleware that edits request and response headers.

package main

import (
	"fmt"
	"net/http"
	"time"

	"github.com/kenkyu392/umbrella"
)

func main() {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "request: %v response: %v",
			r.Header.Get("X-Request-Id"),
			w.Header().Get("X-Response-Id"),
		)
	})

	m := http.NewServeMux()

	// You can embed values in request and response headers.
	mw1 := umbrella.RequestHeader(func(h http.Header) {
		h.Set("X-Request-Id",
			fmt.Sprintf("req-%d", time.Now().UnixNano()),
		)
	})
	mw2 := umbrella.ResponseHeader(func(h http.Header) {
		h.Set("X-Response-Id",
			fmt.Sprintf("res-%d", time.Now().UnixNano()),
		)
	})
	m.Handle("/", mw1(mw2(handler)))

	http.ListenAndServe(":3000", m)
}

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AllowContentType added in v0.2.0

func AllowContentType(contentTypes ...string) func(http.Handler) http.Handler

AllowContentType is middleware that allows a request only if any of the specified strings is included in the Content-Type header. Returns 415 Unsupported Media Type status if the request has a type that is not allowed.

func AllowHTTPHeader

func AllowHTTPHeader(badStatus int, name string, values ...string) func(http.Handler) http.Handler

AllowHTTPHeader is middleware that allows a request only when one of the specified strings is included in the specified request header.

func AllowMethod added in v0.3.0

func AllowMethod(methods ...string) func(http.Handler) http.Handler

AllowMethod is a middleware that returns a 405 Method Not Allowed status if the request method is not one of the given methods.

func AllowUserAgent

func AllowUserAgent(userAgents ...string) func(http.Handler) http.Handler

AllowUserAgent is middleware that allows a request only if any of the specified strings is included in the User-Agent header. Returns 403 Forbidden status if the request has a user-agent that is not allowed.

func CacheControl added in v0.3.0

func CacheControl(opts ...string) func(http.Handler) http.Handler

CacheControl adds the Cache-Control header.

func Clickjacking added in v0.2.0

func Clickjacking(opt string) func(http.Handler) http.Handler

Clickjacking mitigates clickjacking attacks by limiting the display of iframe.

func ContentSniffing added in v0.2.0

func ContentSniffing() func(http.Handler) http.Handler

ContentSniffing adds a header for Content-Type sniffing vulnerability countermeasures.

func Context

func Context(f ContextFunc) func(http.Handler) http.Handler

Context is middleware that edits the context of the request.

func DisallowContentType added in v0.2.0

func DisallowContentType(contentTypes ...string) func(http.Handler) http.Handler

DisallowContentType is middleware that disallow a request only if any of the specified strings is included in the Content-Type header. Returns 415 Unsupported Media Type status if the request has a type that is not allowed.

func DisallowHTTPHeader

func DisallowHTTPHeader(badStatus int, name string, values ...string) func(http.Handler) http.Handler

DisallowHTTPHeader is middleware that disallows a request only when one of the specified strings is included in the specified request header.

func DisallowMethod added in v0.3.0

func DisallowMethod(methods ...string) func(http.Handler) http.Handler

DisallowMethod is a middleware that returns a 405 Method Not Allowed status if the request method is one of the given methods.

func DisallowUserAgent

func DisallowUserAgent(userAgents ...string) func(http.Handler) http.Handler

DisallowUserAgent is middleware that disallow a request only if any of the specified strings is included in the User-Agent header. Returns 403 Forbidden status if the request has a user-agent that is not allowed.

func HSTS added in v0.2.0

func HSTS(maxAge int, opt string) func(http.Handler) http.Handler

HSTS adds the Strict-Transport-Security header. Proper use of this header will mitigate stripping attacks.

func NoCache added in v0.3.0

func NoCache() func(http.Handler) http.Handler

NoCache adds the Cache-Control to disable the cache.

func RealIP added in v0.3.0

func RealIP() func(http.Handler) http.Handler

RealIP is middleware that overwrites RemoteAddr of http.Request with X-Forwarded-For or X-Real-IP header. Validation of the X-Forwarded-For header is done from right to left.

func Recover added in v0.3.0

func Recover(out io.Writer) func(http.Handler) http.Handler

Recover is a middleware that recovers from panic and records a stack trace and returns a 500 Internal Server Error status.

func RequestHeader added in v0.2.0

func RequestHeader(fs ...HeaderFunc) func(http.Handler) http.Handler

RequestHeader is middleware that edits the header of the request.

func ResponseHeader added in v0.2.0

func ResponseHeader(fs ...HeaderFunc) func(http.Handler) http.Handler

ResponseHeader is middleware that edits the header of the response.

func Timeout added in v0.2.0

func Timeout(d time.Duration) func(http.Handler) http.Handler

Timeout cancels the context at the given time. Returns 504 Gateway Timeout status if a timeout occurs.

func Use added in v0.3.0

func Use(middlewares ...func(http.Handler) http.Handler) func(http.Handler) http.Handler

Use creates a single middleware that executes multiple middlewares.

Types

type ContextFunc

type ContextFunc func(ctx context.Context) context.Context

ContextFunc ...

type HeaderFunc added in v0.2.0

type HeaderFunc func(header http.Header)

HeaderFunc ...

func CacheControlHeaderFunc added in v0.3.0

func CacheControlHeaderFunc(opts ...string) HeaderFunc

CacheControlHeaderFunc returns a HeaderFunc that adds a Cache-Control header.

func ClickjackingHeaderFunc added in v0.2.0

func ClickjackingHeaderFunc(opt string) HeaderFunc

ClickjackingHeaderFunc returns a HeaderFunc to mitigate a clickjacking vulnerability.

func ContentSniffingHeaderFunc added in v0.2.0

func ContentSniffingHeaderFunc() HeaderFunc

ContentSniffingHeaderFunc returns a HeaderFunc for Content-Type sniffing vulnerability countermeasure.

func HSTSHeaderFunc added in v0.2.0

func HSTSHeaderFunc(maxAge int, opt string) HeaderFunc

HSTSHeaderFunc returns a HeaderFunc that adds a Strict-Transport-Security header.

func NoCacheHeaderFunc added in v0.3.0

func NoCacheHeaderFunc() HeaderFunc

NoCacheHeaderFunc returns the HeaderFunc to add the Cache-Control header that disables the cache.

Jump to

Keyboard shortcuts

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