[3.0] Address issues with proxy lookups - #9540
Conversation
The 3.0 version of SimpleMachines#9229
|
@sbulen, Please review. I did adjust how your logic worked, but I managed to accomplish the same goals, I believe. The matchToCIDR should be the same, while getUserIP was what I adjusted. |
|
I applied this on top of The CIDR rewrite fixes three crashesWorth noting for anyone wondering whether this is needed,
The Blocking1. Fatal on any install with backward compatibility off.
reached from 2. It now takes the last IP in the header rather than the first. The headline item in #9229 is "Properly uses FIRST ip in header list, not last, for user IP, per RFC 7239", and 2.1 does So it is a change in behaviour against 3. Dangling loop variable in the "both IPs are private" fallback. if (!isset(static::$user_ip) && !$remote_addr->isValid(FILTER_FLAG_GLOBAL_RANGE)) {
static::$user_ip = $ip->simplified();
}
4. Entries in 2.1 runs each entry through Tests 7, 8 and 9 in #9229 are exactly these cases and they do not pass here. A space after the comma is what an admin will type. Worth resolving before merge5. 6. The two 7. public function isPrivate(): bool
{
return $this->isValid() && !$this->isValid(FILTER_FLAG_GLOBAL_RANGE);
}Minor
|
|
Note the concern raised in #9229 is still open: the ban logic needs to be changed. Existing ban logic enforces a ban on both IPs... Once this logic works, one of those IPs will be your proxy. Ie., a ban might shut down all proxy traffic. |
|
Actually, that is a fairly simple change for 3.0. Added a method to the IP class for For 2.1, I think we could just do as mentioned and not check it. Or implement the same idea for 2.1 to check suggestions to ensure they don't match a proxy ip |
…fficient repeated calls
|
Re-checked at 07df9ee, applied on top of the current Confirmed fixed: the Two new ones, both blocking, and then some smaller items. 1.
|
HTTP_X_FORWARDED_FOR: 173.228.74.9, no server list |
release-3.0 | this PR |
|---|---|---|
REMOTE_ADDR = 127.0.0.1 |
173.228.74.9 |
127.0.0.1 |
REMOTE_ADDR = 10.0.0.2 |
173.228.74.9 |
10.0.0.2 |
That is the plain nginx/Varnish-in-front setup, and it is a regression against release-3.0 as well as against #9229. || (or the if/else the previous revision had) does what the comment says.
2. Saving the security settings destroys every CIDR in proxy_ip_servers
securityConfigVars() runs each entry through (new IP($ip, true))->simplified(). The constructor sets $this->ip = '' for anything that is not a bare IP, and a CIDR is not:
in : 173.245.48.0/20, 103.31.4.0/22, 2400:cb00::/32, 2405:b500::4
out: ,,,2405:b500::4
So an admin who opens Server Settings -> Security and presses Save once silently loses the whole Cloudflare list, and with item 1 above everything then falls back to the proxy's own IP. The / needs splitting off before the cleanup runs.
Two smaller points about the same block: it sits in a static getter that returns config vars and mutates $_POST as a side effect, and it runs before User::$me->checkSession(). The cors_domains normalisation just below it does the same kind of job from inside security() after the session check, which looks like the pattern to follow.
Smaller items
clean()throws on null. The constructor isself|string|null $ipand the file isstrict_types=1, sonew IP(null, true)givesTypeError: trim(): Argument #1 ($string) must be of type string, null given. Not reachable from the current call site, but it is a public constructor.private function clean(?string $raw): stringwith a cast covers it.simplify_ip()still does not clean. The shim callsnew SMF\IP($ip)withoutclean: true, sosimplify_ip(' [::ffff:1.2.3.4] ')returns''where the 2.1 function returns1.2.3.4. One word to fix, though I still think neither shim should be added: neithersimplify_ip()norvalid_localhost_ip()exists inv2.1.7, and [2.1] Address issues with proxy lookups #9229 is still open, so no mod can be calling them (same reasoning asmake_fetch_safe()on [3.0] Fixes broken SNI resolution #9535).valid_localhost_ip()'s docblock also still carries the "only supported in PHP 8.2+" note thatisPrivate()just dropped.- Header values are not cleaned either.
getUserIP()buildsnew self($ip)without the flag, so a bracketed[::ffff:173.228.74.9]in a header is still discarded. - Dropping the private-IP fallback changes LAN behaviour. With a private client behind a private proxy,
release-3.0records192.168.1.9; this records the proxy,10.0.0.2. 2.1 takes the first entry if it is a valid IP at all, rather than requiring global range, so it keeps the client too. Fine if deliberate, but on an intranet forum every member ends up sharing one IP. - The ban concern is only half-addressed.
isRegisteredProxyServer()filters the suggestion list on the ban form, butSecurity::checkBans()still queries bothipandip2, andip2is the proxy. An IP typed in by hand, or a range ban, can still catch proxy traffic. - Cosmetic:
$valid_sender = false;is now a dead initial assignment;new IP($_SERVER['REMOTE_ADDR'])re-instantiates what$remote_addralready holds two lines above;static::$registered_proxy_serversis never invalidated ifproxy_ip_serverschanges during the request;clean($raw)has no parameter type.
The 3.0 version of #9229