mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-10-02 07:25:02 -04:00
With ZM_AUTH_HASH_IPS on, the client address bound into the auth hash was taken from the left-most X-Forwarded-For value whenever the header was present, both when PHP generated the hash (getRemoteAddr()) and when PHP or zms validated it (getAuthUser(), zmLoadAuthUser()). The header is client controlled, so anyone holding a leaked hash could replay it from anywhere by sending the address it was bound to. Add ZM_AUTH_TRUSTED_PROXIES, a list of exact reverse proxy addresses. X-Forwarded-For is now used only when REMOTE_ADDR is one of them, and is read from the right, skipping hops that are themselves listed proxies, so values a client prepends are never chosen. With the option empty, the default, the header is ignored and REMOTE_ADDR is used. PHP (web/includes/Network.php getRemoteAddr()) and C++ (ClientAddress() in zm_utils, used by zmLoadAuthUser()) implement the same rule so generation and validation continue to agree. Every PHP caller already routes through getRemoteAddr(), so session.php and auth.php need no change. Reverse proxy users who enable ZM_AUTH_HASH_IPS must list their proxy in the new option; until they do, hashes bind to the proxy address, which still validates but no longer distinguishes clients. This is the behaviour change that the #4921 work avoided by trusting the header. The option is added through ConfigData only, like other recent options; zmupdate.pl --freshen inserts it, zms falls back to the compiled-in default and PHP treats an undefined constant as empty, so no schema migration is needed. Tests: ClientAddress Catch2 case; tests/php/test_remote_addr.php updated for the trusted-proxy rule. refs GHSA-72rf-54rm-798c Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit acea5889dec0826f595cb736147a5fdc9c94a2a9)