umbrella

package module
v0.5.0 Latest Latest
Warning

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

Go to latest
Published: Apr 3, 2021 License: MIT Imports: 13 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

Middleware

Middleware Description
Use Creates a single middleware that executes multiple middleware.
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 manipulates request scope context.
Stampede Stampede provides a simple cache middleware that is valid for a specified amount of time.
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 middleware controls the request based on the User-Agent header of the request.
AllowContentType/DisallowContentType Allow/DisallowContentType middleware controls the request based on the Content-Type header of the request.
AllowAccept/DisallowAccept Allow/DisallowAccept middleware controls the request based on the Accept header of the request.
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 middleware.

Example :
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 middleware.
	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.

Example :
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.

Example :
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.

Example :
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)
}
Stampede

Stampede provides a simple cache middleware that is valid for a specified amount of time.

Example :
package main

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

	"github.com/kenkyu392/umbrella"
)

func main() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		q := r.URL.Query().Get("q")
		log.Printf("Search: %s", q)
		w.WriteHeader(http.StatusOK)
		fmt.Fprintf(w, "Search: %s", q)
	})

	m := http.NewServeMux()

	// Create a middleware with a cache that expires in 5 seconds.
	mw := umbrella.Stampede(time.Second * 5)
	m.Handle("/search", mw(handler))

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

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

Example :
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.

Example :
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.

Example :
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.

Example :
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 manipulates request scope context.

Example :
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 middleware controls the request based on the User-Agent header of the request.

Example :
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 middleware controls the request based on the Content-Type header of the request.

Example :
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)
}
AllowAccept/DisallowAccept

Allow/DisallowAccept middleware controls the request based on the Accept header of the request.

Example :
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.AllowAccept(
		"application/json", "text/json",
	)
	disallows := umbrella.DisallowAccept(
		"text/plain", "text/html",
	)

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

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

Create an access control using the request method.

Example :
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.

Example :
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

View Source
var HoneypotUserAgents = []string{
	"0xSCANNER",
	"20010801",
	"AhrefsBot",
	"Alprazolam",
	"BLEXBot",
	"BOT for JCE",
	"Baiduspider",
	"Gecko/20100115",
	"Gemini",
	"Hakai",
	"Hello",
	"Indy Library",
	"Indy-Library",
	"JDatabaseDriverMysqli",
	"Jorgee",
	"LMAO",
	"MJ12bot",
	"Mappy",
	"Morfeus",
	"NYU",
	"Nessus",
	"Nikto",
	"OpenVAS",
	"Ronin",
	"SemrushBot",
	"Shinka",
	"WPScan",
	"ZmEu",
	"aiohttp",
	"masscan",
	"muhstik",
	"sqlmap",
	"sysscan",
	"union select",
	"yandex",
	"zgrab",
}

HoneypotUserAgents ...

Functions

func AllowAccept added in v0.4.0

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

AllowAccept is middleware that allows a request only if any of the specified strings is included in the Accept header. Returns 406 Not Acceptable status if the request has a type that is not allowed.

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 DisallowAccept added in v0.4.0

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

DisallowAccept is middleware that disallow a request only if any of the specified strings is included in the Accept header. Returns 406 Not Acceptable status if the request has a type that is not allowed.

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 Stampede added in v0.5.0

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

Stampede provides a simple cache middleware that is valid for a specified amount of time. It uses singleflight for caching to prevent thundering-herd and cache-stampede. If this middleware is requested at the same time, it executes the handler only once and shares the execution result with all requests.

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 middleware.

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