secureheaders

package module
v1.4.0 Latest Latest
Warning

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

Go to latest
Published: Aug 11, 2026 License: MIT Imports: 8 Imported by: 2

README

build coverage Docs

secureheaders

secureheaders is an http.Handler middleware that writes a secure baseline of HTTP response headers.

Default headers

SetHeaders sets:

  • Referrer-Policy: strict-origin-when-cross-origin
  • Content-Security-Policy: default-src 'self'; frame-ancestors 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'
  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • X-Xss-Protection: 0
  • Cross-Origin-Opener-Policy: same-origin-allow-popups
  • Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=()

If the request is considered HTTPS, it also sets:

  • Strict-Transport-Security: max-age=31536000; includeSubDomains

Usage

mux := http.NewServeMux()
mux.Handle("GET /", secureheaders.Middleware{
	Handler:               myHandler,
	TrustForwardedHeaders: true,
})

TrustForwardedHeaders controls whether forwarded headers are trusted when checking if a request is secure.

Set it to true only when forwarding headers are set and sanitized by trusted infrastructure (for example, your reverse proxy).

To customize the baseline, start from a copy of the defaults and pass it to the middleware:

headers := secureheaders.DefaultHeaders()
headers.Set("Content-Security-Policy", "default-src 'self'; object-src 'none'")

mux.Handle("GET /", secureheaders.Middleware{
	Handler: myHandler,
	Header:  headers,
})

Security detection

RequestIsSecure(r, trustForwardedHeaders) always trusts r.TLS != nil.

When trustForwardedHeaders is true, it also checks:

  • X-Forwarded-Ssl: on
  • Front-End-Https: on
  • X-Forwarded-Proto
  • Forwarded (proto=https)

For list-valued forwarding headers, the first hop is used.

CSP builder

BuildContentSecurityPolicyForURLs(urls...) applies automatic destination inference to each URL. Use BuildContentSecurityPolicy(resources...) when a URL needs explicit or combined destinations. A Resource separates the URL from the browser request destinations it permits. The URL's scheme, host and port supply the CSP source expression; paths, queries and fragments do not restrict the permission.

Behavior:

  • Starts with a baseline policy: default-src 'self'; frame-ancestors 'none'; object-src 'none'; base-uri 'self'; form-action 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self'; connect-src 'self'.

  • Callers must parse and validate resource URLs from trusted application configuration; the builder does not sanitize them.

  • ResourceDestinationAuto, the zero value, infers destinations:

    • ws:///wss:// URLs select connect-src;
    • an explicit list of common script, style, image and font extensions (including web fonts such as .woff2, .otf and .eot) is consulted next;
    • extensions not on that list use the local MIME database (mime.TypeByExtension), matching media types case-insensitively and mapping text/javascript, application/javascript and application/ecmascript -> script-src, text/css -> style-src, image/* -> img-src and font/* -> font-src;
    • when ordinary extension and MIME inference fail, a trailing @version suffix in the final path segment is ignored and inference is retried;
    • stylesheets select style-src, img-src and font-src; each directive receives the stylesheet's full source expression;
    • URLs still unclassified after extension and MIME matching select connect-src when they use HTTP, HTTPS or a scheme-relative hostname.
  • Automatic inference uses URL conventions, not the actual request context. Hosted script and stylesheet URLs without a recognized asset extension fall back to connect-src and need explicit destinations. A fetched URL with a recognized asset extension also needs ResourceDestinationConnect. The builder does not generate worker-src, media-src, frame-src or manifest-src directives.

  • InferResourceDestinations returns the exact destination bitmask that automatic inference uses. Recognition does not validate CSP source support. ResourceDestinationAuto is zero and has no effect when combined with explicit bits. To extend inference, call this function and combine a recognized result.

  • Explicit destinations bypass inference and select only their named CSP directives. Combine them with |, for example ResourceDestinationStyle | ResourceDestinationImage | ResourceDestinationFont. A value containing an unknown bit causes the resource to be ignored.

  • Use HTTP, HTTPS or scheme-relative URLs with ResourceDestinationConnect for fetch, XMLHttpRequest, EventSource and navigator.sendBeacon; WebSockets require explicit ws:// or wss:// URLs.

  • HTTP, HTTPS, WebSocket and scheme-relative URLs with hosts are supported. Nil URLs, URLs without hosts and unsupported schemes are ignored.

  • Hosts must match the CSP host-source grammar. IPv6 literals and hostnames containing underscores are ignored; internationalized hostnames must use their ASCII A-label (Punycode) form.

  • A scheme-relative URL produces a schemeless source. For an HTTP protected resource it permits HTTP and HTTPS; for HTTPS it permits HTTPS only. It does not permit WebSocket connections; use an explicit ws:// or wss:// URL for those. A scheme-relative * host without a port is ignored.

See the BuildContentSecurityPolicyForURLs package example and the BuildContentSecurityPolicy package example.

Extra headers

To add additional response headers, wrap your handler around the middleware or set them in the wrapped handler itself after middleware processing.

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func BuildContentSecurityPolicy

func BuildContentSecurityPolicy(resources ...Resource) (value string)

BuildContentSecurityPolicy returns a Content-Security-Policy header value.

Each resource contributes a host source expression to its selected destinations. ResourceDestinationAuto applies its documented URL inference. Other destination values may be combined with bitwise OR. Use BuildContentSecurityPolicyForURLs when every URL uses automatic inference.

With no resources, the function returns the default policy, which includes style-src 'unsafe-inline'. HTTP, HTTPS, WebSocket and scheme-relative URLs with hosts are supported. A scheme-relative URL produces a schemeless source. For an HTTP protected resource it permits HTTP and HTTPS; for HTTPS it permits HTTPS only. HTTP, HTTPS and scheme-relative sources do not permit WebSocket connections; use an explicit ws:// or wss:// URL for those. A scheme-relative * host without a port is ignored. Internationalized hostnames must use their ASCII A-label (Punycode) form. Resources with nil URLs, URLs with hosts outside the CSP host-source grammar, unsupported schemes or destination bitmasks containing unknown bits do not contribute a source.

Resources must come from trusted application configuration. Callers are responsible for parsing and validating URLs; this function does not sanitize them.

Example
package main

import (
	"fmt"
	"net/url"
	"strings"

	"github.com/linkdata/secureheaders"
)

func main() {
	stylesheet := &url.URL{Scheme: "https", Host: "cdn.example.com", Path: "/site.css"}
	api := &url.URL{Scheme: "https", Host: "api.example.com", Path: "/data"}

	policy := secureheaders.BuildContentSecurityPolicy(
		secureheaders.Resource{
			URL: stylesheet,
			Destination: secureheaders.ResourceDestinationStyle |
				secureheaders.ResourceDestinationFont,
		},
		secureheaders.Resource{URL: api, Destination: secureheaders.ResourceDestinationConnect},
	)
	for directive := range strings.SplitSeq(policy, "; ") {
		if strings.HasPrefix(directive, "style-src ") ||
			strings.HasPrefix(directive, "font-src ") ||
			strings.HasPrefix(directive, "connect-src ") {
			fmt.Println(directive)
		}
	}

}
Output:
style-src 'self' 'unsafe-inline' https://cdn.example.com
font-src 'self' https://cdn.example.com
connect-src 'self' https://api.example.com

func BuildContentSecurityPolicyForURLs added in v1.4.0

func BuildContentSecurityPolicyForURLs(urls ...*url.URL) (value string)

BuildContentSecurityPolicyForURLs returns a Content-Security-Policy header value using automatic destination inference.

Each non-nil URL uses ResourceDestinationAuto, including its ResourceDestinationConnect fallback for otherwise-unclassified hosted HTTP, HTTPS and scheme-relative URLs. Use BuildContentSecurityPolicy with explicit destinations when URL conventions do not match the request context. With no URLs, it returns the default policy. Source validation matches BuildContentSecurityPolicy.

URLs must come from trusted application configuration because permissions apply to origins, not paths.

Example
package main

import (
	"fmt"
	"net/url"
	"strings"

	"github.com/linkdata/secureheaders"
)

func main() {
	script := &url.URL{Scheme: "https", Host: "cdn.example.com", Path: "/app.js"}
	api := &url.URL{Scheme: "https", Host: "api.example.com", Path: "/data"}

	policy := secureheaders.BuildContentSecurityPolicyForURLs(script, api)
	for directive := range strings.SplitSeq(policy, "; ") {
		if strings.HasPrefix(directive, "script-src ") ||
			strings.HasPrefix(directive, "connect-src ") {
			fmt.Println(directive)
		}
	}

}
Output:
script-src 'self' https://cdn.example.com
connect-src 'self' https://api.example.com

func DefaultHeaders

func DefaultHeaders() http.Header

DefaultHeaders returns a copy of the default security headers used by SetHeaders.

func RequestIsSecure

func RequestIsSecure(hr *http.Request, trustForwardedHeaders bool) (yes bool)

RequestIsSecure reports if a request should be considered HTTPS.

It always treats requests with non-nil TLS as secure.

If trustForwardedHeaders is true, it also honors the forwarding headers X-Forwarded-Ssl, Front-End-Https, X-Forwarded-Proto and Forwarded.

For list-valued forwarding headers, only the first hop is used.

func SetHeaders

func SetHeaders(src http.Header, hw http.ResponseWriter, ishttps bool)

SetHeaders sets the response headers to the values in src. If src is nil, the default security headers are used.

If ishttps is false, Strict-Transport-Security is not set.

Types

type Middleware

type Middleware struct {
	http.Handler             // Handler receives the request after security headers are set.
	Header       http.Header // The headers to set. If nil, uses the default security headers.
	// TrustForwardedHeaders enables forwarded-header HTTPS detection
	// (X-Forwarded-Ssl, Front-End-Https, X-Forwarded-Proto and Forwarded).
	// Enable only when these headers are set and sanitized by trusted
	// infrastructure.
	TrustForwardedHeaders bool
}

Middleware wraps an HTTP handler and sets secure default response headers before delegating to the wrapped handler.

The embedded Handler must be non-nil.

func (Middleware) ServeHTTP

func (m Middleware) ServeHTTP(hw http.ResponseWriter, hr *http.Request)

ServeHTTP sets the security headers on the response and then delegates to the wrapped Handler. Strict-Transport-Security is included only when the request is considered secure (see RequestIsSecure and TrustForwardedHeaders).

type Resource added in v1.2.0

type Resource struct {
	// URL identifies the resource.
	//
	// Its scheme, host and port form the CSP source expression. Its path, query
	// and fragment do not restrict that expression. A nil URL causes the
	// resource to be ignored.
	URL *url.URL

	// Destination selects the directives that permit the resource.
	//
	// Its zero value, [ResourceDestinationAuto], infers destinations from URL.
	// Other values may be combined with bitwise OR.
	Destination ResourceDestination
}

Resource describes a URL used by a generated Content-Security-Policy.

URL supplies the CSP source expression. Destination selects the directives that permit the resource.

type ResourceDestination added in v1.2.0

type ResourceDestination uint32

ResourceDestination is a bitmask selecting CSP directives for a Resource.

Combine explicit destinations with bitwise OR. A resource whose destination contains an unknown bit does not contribute a source.

const (
	// ResourceDestinationScript selects script-src.
	ResourceDestinationScript ResourceDestination = 1 << iota

	// ResourceDestinationStyle selects style-src.
	ResourceDestinationStyle

	// ResourceDestinationImage selects img-src.
	ResourceDestinationImage

	// ResourceDestinationFont selects font-src.
	ResourceDestinationFont

	// ResourceDestinationConnect selects connect-src.
	//
	// Use an HTTP, HTTPS or scheme-relative URL for fetch, XMLHttpRequest,
	// EventSource and navigator.sendBeacon. WebSocket connections require a ws
	// or wss URL.
	ResourceDestinationConnect
)
const ResourceDestinationAuto ResourceDestination = 0

ResourceDestinationAuto infers destinations from the resource URL.

As the zero value, it applies when no explicit destination bits are set and has no effect when combined with explicit bits. To extend inference, combine a recognized result from InferResourceDestinations with explicit bits. WebSocket URLs select ResourceDestinationConnect. Conventional scripts, stylesheets, images and fonts are inferred from the path extension and registered MIME type; MIME matching is case-insensitive. When ordinary extension inference fails, a trailing @version suffix in the final path segment is ignored, so app.js@4.4.1 is inferred as JavaScript. An inferred stylesheet selects ResourceDestinationStyle, ResourceDestinationImage and ResourceDestinationFont. An otherwise-unclassified HTTP, HTTPS or scheme-relative URL with a hostname selects ResourceDestinationConnect.

Inference uses URL conventions, not the actual request context. Hosted script and stylesheet URLs without a recognized asset extension fall back to ResourceDestinationConnect and need explicit destinations. A fetched URL with a recognized asset extension also needs ResourceDestinationConnect. The builder does not generate worker-src, media-src, frame-src or manifest-src directives.

func InferResourceDestinations added in v1.3.0

func InferResourceDestinations(u *url.URL) (destinations ResourceDestination, recognized bool)

InferResourceDestinations reports the destinations ResourceDestinationAuto infers for u.

The result is (ResourceDestinationAuto, false) for a nil URL or when no automatic rule matches. Inference does not otherwise validate CSP source support or determine the application's request context.

Jump to

Keyboard shortcuts

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