Class SourceThrottle
MAX_FAILURES failed attempts per source in a window of WINDOW_MS, after which every attempt from that source is refused until the window ends, whatever the user name. It is the per-source half of the throttle the SignIn survey's D-19 asks for (CC-LOGIN-SERVER-CORE), beside the per-account back-off of UserAuthentication: a stranger who names an account cannot lock it, and a scanner who names many accounts is stopped at its source. It also admits one event per key per interval (acquire(String, long)), for what must not repeat - a password reset mail per account. Modelled on the Mindus License System's RateLimiter (CC-MLS-HARDEN), which lives in another bundle and is not public.Successful attempts count nothing. Everything is in memory and bounded: a source is held for its window and swept once it has expired (at most once a minute, and whenever a table is full), at most MAX_ENTRIES sources and as many keys are held, and while a table is all live a new source's failure is not recorded and a new key is refused - a flood of distinct addresses costs memory to nobody and holds nobody back for longer than one window. The clock is injected as a monotonic millisecond counter, so that the tests drive time.
What the source is: the client's address as the geolocation resolves it (sourceOf(SocketAddress,ForwardedHeaders,TrustedProxies)): the address of the WebSocket connection as the server sees it, or, when that connection comes from a proxy the server setting $geo.trustedProxies names, the client address that proxy forwarded. Behind an untrusted proxy every client shares the proxy's address, as they share it for geolocation.
An IPv6 client is counted by its /64 network (keyOf(InetAddress)): a host is commonly given a whole /64 and changes its address within it at will, so the address alone would be a new source at every attempt. A link-local address is counted as itself, as every host of every link has the same /64.
A client whose address is unknown (UNKNOWN_SOURCE) is never counted: all such clients would share the one key, and the failures of one would hold back every other (CC-FIX-SIGNIN-THROTTLE-SOURCE). Its failed attempts are counted apart (getUnknownFailures()) and logged at most once a minute; the per-account back-off of UserAuthentication holds for it as for everybody.
- Author:
- Christopher Mindus
Field Summary
FieldsModifier and TypeFieldDescriptionstatic final intThe most sources and keys held at once.static final intThe failed attempts a source may make in one window: 20.static final StringThe source of a client whose address is unknown: never held back and never counted per source, see the class description.static final longThe window in milliseconds: 15 minutes.Constructor Summary
ConstructorsConstructorDescriptionConstructs the throttle on the JVM's monotonic clock.SourceThrottle(LongSupplier clock) Constructs the throttle on a clock.Method Summary
Modifier and TypeMethodDescriptionbooleanAdmits one event for a key, or refuses it while the key is held from an earlier event.longGets the failed attempts of clients whose address was unknown, which no source was counted for.longGets how long a source is held back.static StringkeyOf(InetAddress address) Gets the source key of an address: an IPv4 address is its own source; an IPv6 address is counted by its /64 network, written as its first four groups followed by::/64, except a link-local one, which is its own source without its scope.booleanCounts one failed attempt of a source.voidGives a key back before its interval is over: for a request that was admitted and then sent nothing (a refused mail relay), so that the next request is not held back by a mail that never went (CC-FIX-SIGNIN-ACCOUNT-MAIL).intsize()Gets the count of sources and keys held, expired ones included until the next sweep.static StringsourceOf(SocketAddress address) Gets the source key of a client from its remote address.static StringsourceOf(SocketAddress address, ClientAddressResolver.ForwardedHeaders headers, ClientAddressResolver.TrustedProxies trusted) Gets the source key of a client from its connection, the forwarded-address headers of its upgrade request and the trusted proxies, resolved exactly as the session geolocation resolves the client address (ClientAddressResolver.resolve(InetAddress, ClientAddressResolver.ForwardedHeaders, ClientAddressResolver.TrustedProxies)): the connection's address, unless it is a trusted proxy's and the headers name the client.
Field Details
MAX_FAILURES
public static final int MAX_FAILURESThe failed attempts a source may make in one window: 20.- See Also:
WINDOW_MS
public static final long WINDOW_MSThe window in milliseconds: 15 minutes.- See Also:
MAX_ENTRIES
public static final int MAX_ENTRIESThe most sources and keys held at once.- See Also:
UNKNOWN_SOURCE
The source of a client whose address is unknown: never held back and never counted per source, see the class description.- See Also:
Constructor Details
SourceThrottle
public SourceThrottle()Constructs the throttle on the JVM's monotonic clock.SourceThrottle
Constructs the throttle on a clock.- Parameters:
clock- The clock: milliseconds, monotonic, any origin.
Method Details
sourceOf
Gets the source key of a client from its remote address.- Parameters:
address- The remote address, null when unknown.- Returns:
- The source key of the address (
keyOf(InetAddress)), orUNKNOWN_SOURCEwhen there is none.
sourceOf
public static String sourceOf(SocketAddress address, ClientAddressResolver.ForwardedHeaders headers, ClientAddressResolver.TrustedProxies trusted) Gets the source key of a client from its connection, the forwarded-address headers of its upgrade request and the trusted proxies, resolved exactly as the session geolocation resolves the client address (ClientAddressResolver.resolve(InetAddress, ClientAddressResolver.ForwardedHeaders, ClientAddressResolver.TrustedProxies)): the connection's address, unless it is a trusted proxy's and the headers name the client.- Parameters:
address- The remote address of the connection, null when unknown.headers- The forwarded headers, null for none.trusted- The trusted proxies, null for none.- Returns:
- The source key of the resolved address (
keyOf(InetAddress)), orUNKNOWN_SOURCEwhen there is none.
keyOf
Gets the source key of an address: an IPv4 address is its own source; an IPv6 address is counted by its /64 network, written as its first four groups followed by::/64, except a link-local one, which is its own source without its scope.- Parameters:
address- The address, null when unknown.- Returns:
- The source key, or
UNKNOWN_SOURCEwhen there is no address.
heldBack
Gets how long a source is held back.- Parameters:
source- The source key.- Returns:
- Zero when the source may attempt, otherwise the milliseconds until it may; always zero for a client whose address is unknown.
onFailure
Counts one failed attempt of a source.- Parameters:
source- The source key.- Returns:
- true when the source is now held back, false when it may still attempt; always false for a client whose address is unknown, whose failure is counted apart.
acquire
Admits one event for a key, or refuses it while the key is held from an earlier event.- Parameters:
key- The key, e.g. "reset:" followed by the lower-cased user name.interval- The interval in milliseconds the key is held for once admitted.- Returns:
- true when admitted (the key is now held for the interval), false when refused: the key is held, or it is new and the table holds its maximum of live keys.
release
Gives a key back before its interval is over: for a request that was admitted and then sent nothing (a refused mail relay), so that the next request is not held back by a mail that never went (CC-FIX-SIGNIN-ACCOUNT-MAIL). A key that is not held is left alone.- Parameters:
key- The key, as given toacquire(String, long).
getUnknownFailures
public long getUnknownFailures()Gets the failed attempts of clients whose address was unknown, which no source was counted for.- Returns:
- The count since the throttle was constructed.
size
public int size()Gets the count of sources and keys held, expired ones included until the next sweep.- Returns:
- The count.