Documentation
¶
Index ¶
- Constants
- Variables
- func BindJSONBody(r *http.Request, w http.ResponseWriter, v *validation.SchemaValidator, ...) error
- func CSPNoncePerRequest(r *http.Request) (nonce string, rWithNonce *http.Request)
- func CSPNoncePerSession(cookieManager CSPNoncePerSessionCookieManager, w http.ResponseWriter, ...) (nonce string, rWithNonce *http.Request)
- func CheckContentType(raws []string) func(next http.Handler) http.Handler
- func ConstructInternalRedirectURI(ctx context.Context, redirectURI string) string
- func CookieDomainWithoutPort(host string) string
- func GetCSPNonce(ctx context.Context) string
- func GetHost(r *http.Request, trustProxy bool) string
- func GetIP(r *http.Request, trustProxy bool) (ip string)
- func GetProto(r *http.Request, trustProxy bool) string
- func GetRedirectURI(r *http.Request, trustProxy bool) (out string, err error)
- func GetWithContext(ctx context.Context, c *http.Client, url string) (resp *http.Response, err error)
- func HeadWithContext(ctx context.Context, c *http.Client, url string) (resp *http.Response, err error)
- func HealthCheckHandler(w http.ResponseWriter, r *http.Request)
- func HostRelative(u *url.URL) *url.URL
- func ImageCSP(next http.Handler) http.Handler
- func IsJSONContentType(contentType string) bool
- func IsLoopbackHost(host string) bool
- func IsPubliclyRoutable(addr netip.Addr) bool
- func MatchHostPattern(patterns []string, host string) bool
- func NewExternalClient(timeout time.Duration) *http.Client
- func NewExternalClientWithOptions(timeout time.Duration, opts ExternalClientOptions) *http.Client
- func NewSSRFSafeExternalClient(timeout time.Duration, opts SSRFSafeExternalClientOptions) *http.Client
- func NoCache(next http.Handler) http.Handler
- func NoStore(next http.Handler) http.Handler
- func ParseJSONBody(r *http.Request, w http.ResponseWriter, parse func(io.Reader, any) error, ...) error
- func PermissionsPolicyHeader(next http.Handler) http.Handler
- func PostFormWithContext(ctx context.Context, c *http.Client, url string, data url.Values) (resp *http.Response, err error)
- func PostWithContext(ctx context.Context, c *http.Client, url string, contentType string, ...) (resp *http.Response, err error)
- func RedactedRawQuery(rawQuery string) string
- func Redirect(ctx context.Context, w http.ResponseWriter, r *http.Request, ...)
- func ShouldSendSameSiteNone(useragent string, secure bool) bool
- func UpdateCookie(w http.ResponseWriter, cookie *http.Cookie)
- func WithCSPNonce(ctx context.Context, nonce string) context.Context
- func WriteJSONResponse(ctx context.Context, w http.ResponseWriter, resp *api.Response)
- func XContentTypeOptionsNosniff(next http.Handler) http.Handler
- func XFrameOptionsDeny(next http.Handler) http.Handler
- func XRobotsTag(next http.Handler) http.Handler
- type BodyDefaulter
- type CSPDirective
- type CSPDirectiveName
- type CSPDirectives
- type CSPHashSource
- type CSPHostSource
- type CSPKeywordSourceLevel1
- type CSPKeywordSourceLevel3
- type CSPNoncePerSessionCookieManager
- type CSPNonceSource
- type CSPSchemeSource
- type CSPSource
- type CSPSources
- type CookieDef
- type CookieManager
- type CrossOriginProtection
- type ExternalClientOptions
- type FileServer
- type FileServerIndexHTMLTemplateDataKeyType
- type FilesystemCache
- type FlashMessage
- type FlashMessageCookieManager
- type HTTPHost
- type HTTPOrigin
- type HTTPPermissionsPolicy
- type HTTPProto
- type HTTPReferer
- type HTTPRequestURL
- type InternalRedirectResult
- type JSONOption
- type NetIPResolver
- type PermissionsPolicyAllowlist
- type PermissionsPolicyDirective
- type PermissionsPolicyPolicy
- type RemoteIP
- type Result
- type SSRFSafeExternalClientOptions
- type SafeDialer
- type SourceMapConfig
- type TutorialCookie
- type TutorialCookieManager
- type TutorialCookieName
- type UserAgentString
Constants ¶
const BlockedAddressLogKey = "blocked_by_ssrf_policy"
BlockedAddressLogKey is the field to alert on. It appears on exactly one log message, so filtering for it yields every outbound fetch this deployment refused on address grounds and nothing else.
const BodyMaxSize = 1024 * 1024 * 10
const InsecureFetchAddressAllowedFlag = "http.insecure_fetch_address_allowed"
InsecureFetchAddressAllowedFlag names the setting that lifts the restriction, so whoever reads the log does not have to go looking for it.
const MaxResponseBytes int64 = 2 * 1024 * 1024
MaxResponseBytes caps the response body of every fetch of a URL a project supplied. 2 MiB is orders of magnitude above any legitimate response on these paths -- a webhook result, an OIDC discovery document, a JWK set, an SMS gateway's reply -- and low enough that a hostile destination cannot exhaust memory.
Without it the reads on these paths are unbounded: a project admin could point a blocking hook at a host that streams indefinitely and take the server down, no address rule involved. The cap counts DECOMPRESSED bytes, because it is applied above the transport's transparent gzip handling; a small compressed body that expands without bound is refused too.
A fetch that needs a tighter bound still enforces its own: the CIMD document limit of 5120 bytes is set by the OAuth spec, not by this.
const RedactedQueryParamValue = "redacted"
Variables ¶
var BlockedAddressLogger = slogutil.NewLogger("ssrf-address-policy")
var CSPNonceCookieDef = &CookieDef{ NameSuffix: "csp_nonce", Path: "/", SameSite: http.SameSiteNoneMode, }
CSPNonceCookieDef is a HTTP session cookie. The nonce has to be stable within a browsing session because Turbo uses XHR to load new pages. If nonce changes on every page load, the script in the new page cannot be run in the current page due to different nonce.
var CSPSchemeSourceHTTPS = CSPSchemeSource{Scheme: "https"}
var DefaultPermissionsPolicy = []PermissionsPolicyPolicy{ {PermissionsPolicyDirectiveAccelerometer, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveAmbientLightSensor, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveAutoplay, PermissionsPolicyAllowlistAll}, {PermissionsPolicyDirectiveBattery, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveBluetooth, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveBrowsingTopics, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveCamera, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveDisplayCapture, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveDocumentDomain, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveEncryptedMedia, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveExecutionWhileNotRendered, PermissionsPolicyAllowlistAll}, {PermissionsPolicyDirectiveExecutionWhileOutOfViewport, PermissionsPolicyAllowlistAll}, {PermissionsPolicyDirectiveFullscreen, PermissionsPolicyAllowlistAll}, {PermissionsPolicyDirectiveGamepad, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveGeolocation, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveGyroscope, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveHid, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveIdentityCredentialsGet, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveIdleDetection, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveLocalFonts, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveMagnetometer, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveMicrophone, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveMidi, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveOtpCredentials, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectivePayment, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectivePictureInPicture, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectivePublickeyCredentialsCreate, PermissionsPolicyAllowlistSelf}, {PermissionsPolicyDirectivePublickeyCredentialsGet, PermissionsPolicyAllowlistSelf}, {PermissionsPolicyDirectiveScreenWakeLock, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveSerial, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveSpeakerSelection, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveStorageAccess, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveUsb, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveWebShare, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveWindowManagement, PermissionsPolicyAllowlistNone}, {PermissionsPolicyDirectiveXrSpatialTracking, PermissionsPolicyAllowlistNone}, }
* Enabled features: * - autoplay=* * - execution-while-not-rendered=* * - execution-while-out-of-viewport=* * - fullscreen=* * - publickey-credentials-create=(self) (for WebAuthn) * - publickey-credentials-get=(self) (for WebAuthn)
var DependencySet = wire.NewSet( wire.Struct(new(FlashMessage), "*"), wire.Struct(new(TutorialCookie), "*"), MakeHTTPOrigin, GetRequestURL, )
var ErrBlockedAddress = errors.New("httputil: address is not publicly routable")
ErrBlockedAddress is returned when SafeDialer refuses to connect because the destination is not publicly routable.
Call sites that fetch a URL supplied by a project's configuration match on this so the refusal can be reported as a policy decision rather than as just another connection failure -- an operator has to be able to tell "we blocked this" apart from "the host was down".
var ErrResponseTooLarge = errors.New("httputil: response exceeds the maximum size")
ErrResponseTooLarge is returned by a read against a response body that exceeds MaxResponseBytes. It surfaces wherever the caller reads the body -- io.ReadAll, a JSON decode, a schema validation -- so a caller that already handles a malformed response handles this too.
var FileServerIndexHTMLtemplateDataKey = FileServerIndexHTMLTemplateDataKeyType{}
var FlashMessageTypeCookieDef = &CookieDef{ NameSuffix: "flash_message_type", Path: "/", SameSite: http.SameSiteNoneMode, }
FlashMessageTypeCookieDef is a HTTP session cookie.
var JSONResponseWriterLogger = slogutil.NewLogger("json-response-writer")
var JSONTooLarge = apierrors.RequestEntityTooLarge.WithReason("JSONTooLarge")
var SensitiveQueryParams = []string{
"id_token_hint",
"login_hint",
"code",
"token",
}
SensitiveQueryParams lists query parameter names whose values must never appear verbatim in logs (e.g. request URLs), because they can carry identity tokens, PII, or one-time credentials.
var TutorialCookieNames = []TutorialCookieName{ SignupLoginTutorialCookieName, SettingsTutorialCookieName, }
Functions ¶
func BindJSONBody ¶
func BindJSONBody(r *http.Request, w http.ResponseWriter, v *validation.SchemaValidator, payload any, options ...JSONOption) error
func CSPNoncePerRequest ¶
func CSPNoncePerSession ¶
func CSPNoncePerSession(cookieManager CSPNoncePerSessionCookieManager, w http.ResponseWriter, r *http.Request) (nonce string, rWithNonce *http.Request)
func ConstructInternalRedirectURI ¶
ConstructInternalRedirectURI is to construct a redirect uri that is only for internal use, for example, redirecting to the auth ui from authorization endpoint.
func CookieDomainWithoutPort ¶
CookieDomainWithoutPort derives host from r. If host has port, the port is removed. If host-1 is longer than ETLD+1, host-1 is returned. If ETLD+1 cannot be derived, an empty string is returned. The return value never have port.
func GetCSPNonce ¶
func GetWithContext ¶
func GetWithContext(ctx context.Context, c *http.Client, url string) (resp *http.Response, err error)
GetWithContext is a compat method for http.Client.Get
func HeadWithContext ¶
func HeadWithContext(ctx context.Context, c *http.Client, url string) (resp *http.Response, err error)
HeadWithContext is a compat method for http.Client.Head
func HealthCheckHandler ¶
func HealthCheckHandler(w http.ResponseWriter, r *http.Request)
HealthCheckHandler is basic handler for server health check
func ImageCSP ¶
ImageCSP sandboxes any response that a browser ends up treating as a document.
The images endpoint serves arbitrary uploaded bytes and is same origin with the Auth UI in the default deployment. Handlers are responsible for never declaring an active Content-Type, and this is the backstop if one slips through: as a document the response gets a unique origin and no script execution, and as an <img> subresource the directives do not apply.
func IsJSONContentType ¶
func IsLoopbackHost ¶
IsLoopbackHost reports whether host -- as returned by url.URL.Hostname(), which strips the brackets from an IPv6 literal like "[::1]:3000" -- names a loopback interface: "localhost", or the IPv4/IPv6 loopback literals "127.0.0.1" and "::1". Per RFC 8252 §7.3, native/CLI OAuth clients use any of these interchangeably for their redirect_uri callback listener.
This checks the literal hostname string, not a resolved IP address: it is for validating a redirect_uri that Authgear itself never connects to (unlike the SSRF concern IsPubliclyRoutable addresses for URLs Authgear fetches), so there is no DNS resolution step to filter.
func IsPubliclyRoutable ¶
IsPubliclyRoutable reports whether addr is safe to connect to when fetching a URL supplied by a tenant/third party (the SSRF concern docs/specs/cimd.md § SSRF Protection describes, but the check itself is generic and not specific to CIMD): not loopback, not private, not link-local, not multicast, not unspecified, and not one of the additional special-use ranges above -- each of which either embeds an arbitrary (possibly private) IPv4 address, or is otherwise not a real routable destination.
func MatchHostPattern ¶
MatchHostPattern reports whether host matches any of patterns.
Matching is on a hostname only -- never host:port -- and is case-insensitive. A leading "*." matches exactly ONE label, per the RFC 6125 / TLS certificate convention: "*.example.com" matches "a.example.com" but not "a.b.example.com" and not the apex "example.com". A single-label hostname such as "localhost" is a valid pattern.
An empty pattern list matches nothing. Callers whose empty case means "no restriction" check that themselves, so that the two readings of an empty list stay at the call site rather than being buried here.
func NewExternalClientWithOptions ¶
func NewExternalClientWithOptions(timeout time.Duration, opts ExternalClientOptions) *http.Client
NewExternalClientWithOptions returns a client for a destination this deployment configures: the Deno hook runner, object storage, an SMS or captcha vendor's API. Those legitimately address internal hosts, so no address restriction applies here.
For a destination taken from a project's configuration, use NewSSRFSafeExternalClient instead -- that is where the SSRF concern lives, and it cannot be handled here without breaking the call sites above.
func NewSSRFSafeExternalClient ¶
func NewSSRFSafeExternalClient(timeout time.Duration, opts SSRFSafeExternalClientOptions) *http.Client
NewSSRFSafeExternalClient returns a client for fetching a URL whose destination comes from a project's configuration rather than from this deployment: event webhooks, the custom SMS provider, the account migration and phone verification hooks, and an OAuth provider's OIDC discovery document.
Whoever administers a project chooses those URLs, and on a deployment with open sign-up that is any user who created one, so the destination is not trusted to be outside the deployment's own network. SafeDialer is what enforces that; see its documentation for why the check cannot live in a dialer Control hook alone.
It also caps the response body at MaxResponseBytes. A hostile destination that streams without end is as effective against this server as one on an internal address, and neither is the caller's to remember.
Not for the clients whose destination this deployment configures -- the Deno hook runner, object storage, an SMS vendor's API. Those legitimately address internal hosts, and must keep using NewExternalClient.
func NoCache ¶
NoCache allows caches to store a response but requires them to revalidate it before reuse.
func ParseJSONBody ¶
func PostFormWithContext ¶
func PostFormWithContext(ctx context.Context, c *http.Client, url string, data url.Values) (resp *http.Response, err error)
PostFormWithContext is a compat method for http.Client.PostForm
func PostWithContext ¶
func PostWithContext(ctx context.Context, c *http.Client, url string, contentType string, body io.Reader) (resp *http.Response, err error)
PostWithContext is a compat method for http.Client.Post
func RedactedRawQuery ¶
RedactedRawQuery returns rawQuery with the values of SensitiveQueryParams replaced, so it is safe to write to logs. It returns rawQuery unchanged if none of SensitiveQueryParams are present.
func ShouldSendSameSiteNone ¶
func UpdateCookie ¶
func UpdateCookie(w http.ResponseWriter, cookie *http.Cookie)
func WriteJSONResponse ¶
Types ¶
type BodyDefaulter ¶
type BodyDefaulter interface {
SetDefaults()
}
type CSPDirective ¶
type CSPDirective struct {
Name CSPDirectiveName
Value CSPSources
}
func (CSPDirective) String ¶
func (d CSPDirective) String() string
type CSPDirectiveName ¶
type CSPDirectiveName string
const ( // connect-src is not needed when there is no default-src. // CSPDirectiveNameConnectSrc CSPDirectiveName = "connect-src" // font-src is not needed when there is no default-src. // CSPDirectiveNameFontSrc CSPDirectiveName = "font-src" // frame-src is not needed when there is no default-src. // CSPDirectiveNameFrameSrc CSPDirectiveName = "frame-src" // img-src is not needed when there is no default-src. // CSPDirectiveNameImgSrc CSPDirectiveName = "img-src" CSPDirectiveNameObjectSrc CSPDirectiveName = "object-src" CSPDirectiveNameScriptSrc CSPDirectiveName = "script-src" CSPDirectiveNameBaseURI CSPDirectiveName = "base-uri" // CSPDirectiveNameBlockAllMixedContent is deprecated. // See https://www.w3.org/TR/mixed-content/#strict-checking // CSPDirectiveNameBlockAllMixedContent CSPDirectiveName = "block-all-mixed-content" CSPDirectiveNameFrameAncestors CSPDirectiveName = "frame-ancestors" )
type CSPDirectives ¶
type CSPDirectives []CSPDirective
func (CSPDirectives) String ¶
func (d CSPDirectives) String() string
type CSPHashSource ¶
type CSPHashSource struct {
Hash string
}
func (CSPHashSource) CSPLevel ¶
func (s CSPHashSource) CSPLevel() int
func (CSPHashSource) String ¶
func (s CSPHashSource) String() string
type CSPHostSource ¶
func (CSPHostSource) CSPLevel ¶
func (s CSPHostSource) CSPLevel() int
func (CSPHostSource) String ¶
func (s CSPHostSource) String() string
type CSPKeywordSourceLevel1 ¶
type CSPKeywordSourceLevel1 string
const ( CSPSourceNone CSPKeywordSourceLevel1 = "'none'" CSPSourceSelf CSPKeywordSourceLevel1 = "'self'" )
func (CSPKeywordSourceLevel1) CSPLevel ¶
func (_ CSPKeywordSourceLevel1) CSPLevel() int
func (CSPKeywordSourceLevel1) String ¶
func (s CSPKeywordSourceLevel1) String() string
type CSPKeywordSourceLevel3 ¶
type CSPKeywordSourceLevel3 string
const ( // 'unsafe-hashes' is not needed when we no longer specify style-src. // If you want it to allow inline event handler, you should migrate from inline event handler instead. // CSPSourceUnsafeHashes CSPKeywordSourceLevel3 = "'unsafe-hashes'" CSPSourceStrictDynamic CSPKeywordSourceLevel3 = "'strict-dynamic'" )
func (CSPKeywordSourceLevel3) CSPLevel ¶
func (_ CSPKeywordSourceLevel3) CSPLevel() int
func (CSPKeywordSourceLevel3) String ¶
func (s CSPKeywordSourceLevel3) String() string
type CSPNonceSource ¶
type CSPNonceSource struct {
Nonce string
}
func (CSPNonceSource) CSPLevel ¶
func (s CSPNonceSource) CSPLevel() int
func (CSPNonceSource) String ¶
func (s CSPNonceSource) String() string
type CSPSchemeSource ¶
type CSPSchemeSource struct {
Scheme string
}
func (CSPSchemeSource) CSPLevel ¶
func (s CSPSchemeSource) CSPLevel() int
func (CSPSchemeSource) String ¶
func (s CSPSchemeSource) String() string
type CSPSources ¶
type CSPSources []CSPSource
func (CSPSources) Len ¶
func (s CSPSources) Len() int
func (CSPSources) Less ¶
func (s CSPSources) Less(i, j int) bool
func (CSPSources) String ¶
func (s CSPSources) String() string
func (CSPSources) Swap ¶
func (s CSPSources) Swap(i, j int)
type CookieDef ¶
type CookieDef struct {
// NameSuffix means the cookie could have prefix.
NameSuffix string
Path string
// Domain is omitted because it is controlled somewhere else.
// Domain string
AllowScriptAccess bool
SameSite http.SameSite
MaxAge *int
// This flag is the inverse of http cookie host-only-flag (RFC6265 section5.3.6), default false
IsNonHostOnly bool
}
CookieDef defines a cookie that is written to the response. All cookies in our server expects to be created with this definition.
type CookieManager ¶
type CookieManager struct {
Request *http.Request
TrustProxy bool
CookiePrefix string
CookieDomain string
}
func (*CookieManager) ClearCookie ¶
func (f *CookieManager) ClearCookie(def *CookieDef) *http.Cookie
ClearCookie generates a cookie that when set, the cookie is clear.
func (*CookieManager) CookieName ¶
func (f *CookieManager) CookieName(def *CookieDef) string
CookieName returns the full name, that is, CookiePrefix followed by NameSuffix.
func (*CookieManager) GetCookie ¶
GetCookie is wrapper around http.Request.Cookie, taking care of cookie name.
func (*CookieManager) ValueCookie ¶
func (f *CookieManager) ValueCookie(def *CookieDef, value string) *http.Cookie
ValueCookie generates a cookie that when set, the cookie is set to the specified value.
type CrossOriginProtection ¶
type CrossOriginProtection struct{}
func NewCrossOriginProtection ¶
func NewCrossOriginProtection() *CrossOriginProtection
type ExternalClientOptions ¶
type ExternalClientOptions struct {
FollowRedirect bool
Transport http.RoundTripper
}
type FileServer ¶
type FileServer struct {
FileSystem http.FileSystem
AssetsDir string
FallbackToIndexHTML bool
// SourceMap configures how source map (*.map) files are served.
// The zero value serves no source map file.
SourceMap SourceMapConfig
}
FileServer is a specialized version of http.FileServer that assumes files rooted at FileSystem are name-hashed. Cache-control are written specifically for index.html and name-hashed files. When serving index.html, index.html is assumed to be a Go template. FileServer will use the context value FileServerIndexHTMLTemplateDataKey to render.
func (*FileServer) ServeHTTP ¶
func (s *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request)
type FileServerIndexHTMLTemplateDataKeyType ¶
type FileServerIndexHTMLTemplateDataKeyType struct{}
type FilesystemCache ¶
type FilesystemCache struct {
// contains filtered or unexported fields
}
FilesystemCache is a helper to write the response into the tmp directory. The response is then served with http.FileServer, with the advantage of supporting range request and cache validation. If the file is not modified, the response is a 304. For even better performance, we need to add Cache-Control header to take advantage of the fact that the filename is hashed. However, http.FileServer does not support Cache-Control. Unconditionally adding Cache-Control for non-existent file is problematic.
func NewFilesystemCache ¶
func NewFilesystemCache() *FilesystemCache
func (*FilesystemCache) Clear ¶
func (c *FilesystemCache) Clear() error
type FlashMessage ¶
type FlashMessage struct {
Cookies FlashMessageCookieManager
}
func (*FlashMessage) Flash ¶
func (f *FlashMessage) Flash(rw http.ResponseWriter, messageType string)
func (*FlashMessage) Pop ¶
func (f *FlashMessage) Pop(r *http.Request, rw http.ResponseWriter) string
type HTTPOrigin ¶
type HTTPOrigin string
func MakeHTTPOrigin ¶
func MakeHTTPOrigin(proto HTTPProto, host HTTPHost) HTTPOrigin
type HTTPPermissionsPolicy ¶
type HTTPPermissionsPolicy []PermissionsPolicyPolicy
func (HTTPPermissionsPolicy) String ¶
func (p HTTPPermissionsPolicy) String() string
type HTTPReferer ¶
type HTTPReferer string
func GetReferer ¶
func GetReferer(r *http.Request) HTTPReferer
type HTTPRequestURL ¶
type HTTPRequestURL string
func GetRequestURL ¶
func GetRequestURL(r *http.Request, proto HTTPProto, host HTTPHost) HTTPRequestURL
type InternalRedirectResult ¶
InternalRedirectResult is a redirect result that is only for internal use, for example, redirecting to the auth ui from authorization endpoint.
func (*InternalRedirectResult) IsInternalError ¶
func (re *InternalRedirectResult) IsInternalError() bool
func (*InternalRedirectResult) WriteResponse ¶
func (re *InternalRedirectResult) WriteResponse(rw http.ResponseWriter, r *http.Request)
type JSONOption ¶
type JSONOption func(option *jsonOption)
func WithBodyMaxSize ¶
func WithBodyMaxSize(size int64) JSONOption
type NetIPResolver ¶
type NetIPResolver interface {
LookupNetIP(ctx context.Context, network, host string) ([]netip.Addr, error)
}
NetIPResolver is the one *net.Resolver method SafeDialer needs, pulled out as an interface so tests can stub DNS resolution without spinning up a real DNS server. *net.Resolver satisfies it as-is.
type PermissionsPolicyAllowlist ¶
type PermissionsPolicyAllowlist string
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy#allowlist
const ( PermissionsPolicyAllowlistAll PermissionsPolicyAllowlist = "*" PermissionsPolicyAllowlistNone PermissionsPolicyAllowlist = "()" PermissionsPolicyAllowlistSelf PermissionsPolicyAllowlist = "(self)" PermissionsPolicyAllowlistSrc PermissionsPolicyAllowlist = "(src)" )
type PermissionsPolicyDirective ¶
type PermissionsPolicyDirective string
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy#directives
const ( PermissionsPolicyDirectiveAccelerometer PermissionsPolicyDirective = "accelerometer" PermissionsPolicyDirectiveAmbientLightSensor PermissionsPolicyDirective = "ambient-light-sensor" PermissionsPolicyDirectiveAutoplay PermissionsPolicyDirective = "autoplay" PermissionsPolicyDirectiveBattery PermissionsPolicyDirective = "battery" PermissionsPolicyDirectiveBluetooth PermissionsPolicyDirective = "bluetooth" PermissionsPolicyDirectiveBrowsingTopics PermissionsPolicyDirective = "browsing-topics" PermissionsPolicyDirectiveCamera PermissionsPolicyDirective = "camera" PermissionsPolicyDirectiveDisplayCapture PermissionsPolicyDirective = "display-capture" PermissionsPolicyDirectiveDocumentDomain PermissionsPolicyDirective = "document-domain" PermissionsPolicyDirectiveEncryptedMedia PermissionsPolicyDirective = "encrypted-media" PermissionsPolicyDirectiveExecutionWhileNotRendered PermissionsPolicyDirective = "execution-while-not-rendered" PermissionsPolicyDirectiveExecutionWhileOutOfViewport PermissionsPolicyDirective = "execution-while-out-of-viewport" PermissionsPolicyDirectiveFullscreen PermissionsPolicyDirective = "fullscreen" PermissionsPolicyDirectiveGamepad PermissionsPolicyDirective = "gamepad" PermissionsPolicyDirectiveGeolocation PermissionsPolicyDirective = "geolocation" PermissionsPolicyDirectiveGyroscope PermissionsPolicyDirective = "gyroscope" PermissionsPolicyDirectiveHid PermissionsPolicyDirective = "hid" PermissionsPolicyDirectiveIdentityCredentialsGet PermissionsPolicyDirective = "identity-credentials-get" PermissionsPolicyDirectiveIdleDetection PermissionsPolicyDirective = "idle-detection" PermissionsPolicyDirectiveLocalFonts PermissionsPolicyDirective = "local-fonts" PermissionsPolicyDirectiveMagnetometer PermissionsPolicyDirective = "magnetometer" PermissionsPolicyDirectiveMicrophone PermissionsPolicyDirective = "microphone" PermissionsPolicyDirectiveMidi PermissionsPolicyDirective = "midi" PermissionsPolicyDirectiveOtpCredentials PermissionsPolicyDirective = "otp-credentials" PermissionsPolicyDirectivePayment PermissionsPolicyDirective = "payment" PermissionsPolicyDirectivePictureInPicture PermissionsPolicyDirective = "picture-in-picture" PermissionsPolicyDirectivePublickeyCredentialsCreate PermissionsPolicyDirective = "publickey-credentials-create" PermissionsPolicyDirectivePublickeyCredentialsGet PermissionsPolicyDirective = "publickey-credentials-get" PermissionsPolicyDirectiveScreenWakeLock PermissionsPolicyDirective = "screen-wake-lock" PermissionsPolicyDirectiveSerial PermissionsPolicyDirective = "serial" PermissionsPolicyDirectiveSpeakerSelection PermissionsPolicyDirective = "speaker-selection" PermissionsPolicyDirectiveStorageAccess PermissionsPolicyDirective = "storage-access" PermissionsPolicyDirectiveUsb PermissionsPolicyDirective = "usb" PermissionsPolicyDirectiveWindowManagement PermissionsPolicyDirective = "window-management" PermissionsPolicyDirectiveXrSpatialTracking PermissionsPolicyDirective = "xr-spatial-tracking" )
type PermissionsPolicyPolicy ¶
type PermissionsPolicyPolicy struct {
Directive PermissionsPolicyDirective
Allowlist PermissionsPolicyAllowlist
}
type Result ¶
type Result interface {
WriteResponse(rw http.ResponseWriter, r *http.Request)
IsInternalError() bool
}
type SSRFSafeExternalClientOptions ¶
type SSRFSafeExternalClientOptions struct {
// AllowNonPublicAddresses lifts the address restriction entirely. It
// carries http.insecure_fetch_address_allowed.
AllowNonPublicAddresses bool
// AllowedHosts exempts named hosts from the restriction, carrying
// http.insecure_fetch_address_allowed_hosts. Nothing else may widen the
// policy.
AllowedHosts []string
// Sink names the configuration that chose the URL, e.g.
// "hook.blocking_handlers". It appears in the log a refusal writes, so
// that the message says which setting to go and fix.
Sink string
// RootCAs verifies the server certificate against this pool only,
// instead of the system trust store. For a destination inside the
// deployment, issued by a private certificate authority. nil keeps the
// system trust store.
RootCAs *x509.CertPool
}
SSRFSafeExternalClientOptions configures NewSSRFSafeExternalClient.
type SafeDialer ¶
type SafeDialer struct {
Resolver NetIPResolver // nil means net.DefaultResolver
AllowNonPublicAddresses bool
// AllowedHosts names the hosts exempt from the address rules, matched by
// MatchHostPattern. It is the narrow alternative to AllowNonPublicAddresses:
// an operator naming their own internal receiver, rather than opening every
// non-public address.
//
// Exempting a host also exempts it from the rebinding protection, since
// whatever it resolves to is accepted. That is inherent to naming a host you
// trust, and is why the list must never contain a host someone else chooses.
AllowedHosts []string
// DialTimeout bounds the connect itself. Zero means no dial-specific
// deadline, leaving whatever the context and http.Client.Timeout impose.
DialTimeout time.Duration
// Sink names the configuration that chose the destination, e.g.
// "hook.blocking_handlers". It appears in the log a refusal writes; see
// logIfBlockedAddress.
Sink string
}
SafeDialer refuses to connect to an address that is not publicly routable, which is what stops a URL taken from configuration or from a third party being used to reach the deployment's own network.
It implements two rules together, because neither works without the other:
- Resolve the hostname once per dial and connect only to an address validated in that same resolution -- a second, independent resolution at connect time is vulnerable to DNS rebinding.
- Check every address a hostname resolves to, not just the first -- reject the whole hostname if any A/AAAA record is non-publicly-routable, rather than filtering to the routable subset. A mixed answer is an attack signature, not a misconfiguration to accommodate.
AllowNonPublicAddresses is a plain field rather than a config read, so the dialer stays a pure function of its inputs. Whoever constructs it decides the policy; there is no second mechanism that widens it.
func (*SafeDialer) DialContext ¶
DialContext dials addr, and writes the refusal log if the policy rejects it.
The log is emitted here, not at the call sites that fetch a URL, because this is the only place that knows a refusal happened. A caller sees a transport error indistinguishable from an unreachable host, so leaving the log to callers means every future one has to remember to write it.
type SourceMapConfig ¶
type SourceMapConfig struct {
// Enabled sets whether source map files are served at all.
// When it is false, source map files are served as if they did not exist.
Enabled bool
// SentryToken, when non-empty, protects source map files with HTTP basic authentication.
// The token is the password, and the username is ignored.
// Sentry fetches a publicly hosted source map with a configurable header,
// so it can be configured to send `Authorization: Basic <base64 of ":<token>">`.
// See https://docs.sentry.io/platforms/javascript/sourcemaps/uploading/hosting-publicly/
SentryToken string
}
SourceMapConfig configures how FileServer serves source map (*.map) files.
func (SourceMapConfig) IsAuthorized ¶
func (c SourceMapConfig) IsAuthorized(r *http.Request) bool
IsAuthorized tells whether r is allowed to fetch a source map file.
type TutorialCookie ¶
type TutorialCookie struct {
Cookies FlashMessageCookieManager
}
func (*TutorialCookie) Pop ¶
func (t *TutorialCookie) Pop(r *http.Request, rw http.ResponseWriter, name TutorialCookieName) bool
func (*TutorialCookie) SetAll ¶
func (t *TutorialCookie) SetAll(rw http.ResponseWriter)
type TutorialCookieManager ¶
type TutorialCookieName ¶
type TutorialCookieName string
const ( SignupLoginTutorialCookieName TutorialCookieName = "signup_login_tutorial" SettingsTutorialCookieName TutorialCookieName = "settings_tutorial" )
type UserAgentString ¶
type UserAgentString string
Source Files
¶
- addrfilter.go
- blocked_address_log.go
- content_type.go
- context_compat.go
- cookie.go
- cross_origin_protection.go
- csp.go
- deps.go
- etag.go
- ext_client.go
- file_server.go
- filesystem_cache.go
- flash_message.go
- gzip.go
- healthz.go
- host.go
- host_pattern.go
- image_csp.go
- ip.go
- json.go
- loopback.go
- no_cache.go
- no_store.go
- origin.go
- permissions_policy.go
- permissions_policy_header.go
- proto.go
- redact_query.go
- redirect_uri.go
- referer.go
- request_url.go
- response_limit.go
- result.go
- safedialer.go
- samesite.go
- tutorial.go
- user_agent.go
- x_content_type_options_nosniff.go
- x_frame_options_deny.go
- x_robots_tag.go