Documentation
¶
Overview ¶
Package requestorigin answers three questions for every caller that asks them: what scheme did this request arrive over, what origin does this deployment serve it as, and which client sent it.
It exists because the first question was being answered three times. The CSRF middleware compared a whole origin from r.TLS alone, the security-header middleware read X-Forwarded-Proto behind a trusted-proxy gate, and the logout endpoint read the same header with no gate at all. Three answers to one question is one answer that drifts, so all of them now come from here.
Index ¶
- func Matches(r *http.Request, trusted map[string]bool) bool
- func MatchesOrigin(self, origin, referer string, trusted map[string]bool) bool
- func Of(r *http.Request) string
- func Set(origins ...string) map[string]bool
- type Proxies
- func (p Proxies) ClientAddress(r *http.Request) string
- func (p Proxies) ClientAddressOf(remoteAddress string, forwarded []string) string
- func (p Proxies) Empty() bool
- func (p Proxies) IsHTTPS(r *http.Request) bool
- func (p Proxies) Matches(r *http.Request, trusted map[string]bool) bool
- func (p Proxies) Networks() []*net.IPNet
- func (p Proxies) Of(r *http.Request) string
- func (p Proxies) OriginOf(host, scheme string) string
- func (p Proxies) Scheme(r *http.Request) string
- func (p Proxies) SchemeOf(tls bool, remoteAddress, forwardedProto string) string
- func (p Proxies) Trusts(address string) bool
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MatchesOrigin ¶
MatchesOrigin decides whether a request came from somewhere this deployment accepts, given the origin it serves as and the two headers a browser sends.
Origin is preferred and Referer is the fallback, and a request carrying neither is refused rather than allowed. That is the whole cross-site judgement, so it is one function: a second implementation could differ on the "null" origin, which a sandboxed frame and a privacy-stripped navigation both send, and treating that as same-origin would accept exactly the requests this check exists to refuse.
func Set ¶
Set turns configured origin strings into the map Matches takes.
Each value is normalized to scheme and host, so a trailing slash or a path someone pasted from a browser bar does not silently fail to match. A value that names no scheme or no host is dropped rather than stored, because it cannot match an origin and keeping it would suggest it could.
Types ¶
type Proxies ¶
type Proxies struct {
// contains filtered or unexported fields
}
Proxies is the set of peer networks whose forwarded headers this deployment reads. The zero value trusts nothing, which is the correct answer for a listener with no proxy in front of it.
A header arriving from outside the set is treated as absent rather than as false, so a deployment that is behind a proxy but has declared none degrades to the answer it would have given before the proxy existed.
func Compile ¶
Compile turns configured addresses and CIDR blocks into the trust set. A bare address is taken as a single-host network.
Errors name the offending value and leave the configuration key to the caller, since this package does not know which binding it came from.
func FromNetworks ¶
FromNetworks adopts networks a caller compiled elsewhere.
It exists because the public middleware surfaces speak []*net.IPNet, a standard type an application outside this module can construct, while the resolution itself lives on this type.
func (Proxies) ClientAddress ¶
ClientAddress is the address of the caller rather than of the relay in front of it, without a port.
X-Forwarded-For is walked from the right while each hop is one of this deployment's own proxies; the first address outside the set is the client. A chain that is entirely trusted yields its leftmost entry, which is the closest thing to a client it records. A malformed entry abandons the header and returns the peer, because a chain that cannot be parsed cannot be trusted partway.
func (Proxies) ClientAddressOf ¶
ClientAddressOf is ClientAddress over the two facts it reads, for a caller whose request is not a *http.Request.
The walk backwards through the forwarded chain is the part worth having once: it stops at the first hop this deployment does not trust, which is the last address a trusted peer vouched for, and it gives up entirely on an unparseable hop rather than accepting a later one. A second transport reimplementing that would be a second answer to who the caller is, and every rate limit and live bound counts against it.
func (Proxies) Matches ¶
Matches reports whether the request came from this deployment's own origin or one the caller named in trusted, which may be nil.
Origin is preferred, because a browser sets it on exactly the state-changing requests this protects. A literal null Origin is not one: it is what an opaque origin sends, and treating it as absent would fall through to the weaker check below.
Referer is the fallback for a proxy that stripped Origin, and it is read strictly. A missing one is a refusal rather than a pass, since treating absence as trust would make the whole check optional for anything able to omit a header.
The declared origins stay the stronger half of this comparison: a proxy set resolves what this deployment calls itself, and never makes an origin nobody declared acceptable.
func (Proxies) Of ¶
Of reconstructs the origin of the request itself, as scheme and host.
It returns the empty string for a request carrying no Host, which never matches anything.
func (Proxies) OriginOf ¶
OriginOf assembles the origin from a host and an already-resolved scheme, for a caller whose request is not a *http.Request.
func (Proxies) Scheme ¶
Scheme is the scheme the client actually used.
A direct TLS connection outranks every header, since it needs no assertion. Otherwise X-Forwarded-Proto is read, and only when the peer is one of this deployment's declared proxies.
func (Proxies) SchemeOf ¶
SchemeOf is Scheme over the three facts it actually reads, for a caller whose request is not a *http.Request.
The rule is the reason this is one function rather than two: a forwarded header is only evidence, and only from a declared peer, because anybody can send one. A second transport reimplementing that would be a fourth answer to the question this package exists to answer once.