feat: IP ban support (#185) (#188)

This commit is contained in:
Ferywir
2026-06-09 14:15:27 +02:00
committed by GitHub
parent d30bef0a40
commit 20804d9182
12 changed files with 501 additions and 9 deletions
+62
View File
@@ -87,6 +87,68 @@ Recent improvements include:
- Added cache on Database.php and Automation.php and other important files
- Dynamic table prefix support in map tile queries
## Security: IP bans & reverse proxies
The admin **Ban** page can ban by **IP address** in addition to per-account bans
(`Admin/admin.php?p=ban` -> *Ban IP Address*). A banned IP receives an "Access blocked"
page on every game page. Admins and Multihunters are never affected, and the admin
panel itself is always reachable (no self-lockout). IPv4 and IPv6 are supported.
### Configuration (`GameEngine/config.php`)
| Constant | Default | Purpose |
|----------|---------|---------|
| `BAN_IP_ENABLED` | `true` | Master switch for IP-ban enforcement. |
| `IP_TRUSTED_PROXIES` | `""` | Comma-separated proxy IPs/CIDRs allowed to set the forwarded header. |
| `IP_FORWARDED_HEADER` | `"HTTP_X_FORWARDED_FOR"` | `$_SERVER` key read for the real client IP when behind a trusted proxy. |
**Security model:** only `REMOTE_ADDR` (the direct peer) is trusted by default — it
cannot be spoofed. Forwarded headers are honoured **only** when `REMOTE_ADDR` is in
`IP_TRUSTED_PROXIES`. This prevents a visitor from bypassing a ban with a forged
`X-Forwarded-For` header.
### Deployment scenarios
**1. Direct access (no proxy)** — default, nothing to do:
```php
define("IP_TRUSTED_PROXIES", "");
```
**2. Behind a reverse proxy** (Nginx, Nginx Proxy Manager / NPMplus, Traefik, Caddy, …):
```php
// your proxy's address, or a CIDR (e.g. 10.0.0.0/8 / 172.16.0.0/12 for a Docker bridge network)
define("IP_TRUSTED_PROXIES", "10.0.0.1");
define("IP_FORWARDED_HEADER", "HTTP_X_FORWARDED_FOR");
```
The proxy must forward the client IP. Prefer **overwriting** the header with the real
peer rather than appending a client-supplied value (non-spoofable). Nginx example:
```nginx
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
```
**3. Behind Cloudflare:**
```php
define("IP_TRUSTED_PROXIES", "<your origin proxy or the Cloudflare IP ranges>");
define("IP_FORWARDED_HEADER", "HTTP_CF_CONNECTING_IP");
```
> ⚠️ **Important:** behind a proxy, if `IP_TRUSTED_PROXIES` is left empty, every
> visitor is seen with the proxy's IP — a single IP ban would then block everyone.
> Always set it to your proxy's address.
### Verify
Check the resolved IP in the admin **Unified Admin Log** (a login entry shows the
client IP), or temporarily print `$_SERVER['REMOTE_ADDR']` and the forwarded header:
`REMOTE_ADDR` should be your proxy, and the forwarded header should carry the real
client IP.
## Performance Notes
For large worlds (for example `400x400`), generation tasks can be expensive.