geenforce: harden allowlist + fix share-less kiosk client and display scope
- allowlist auth uses remote_addr, not the spoofable first X-Forwarded-For hop (adds _trusted_client_ip + a regression test); rate-limit path unchanged - client psm1: fix Set-StrictMode crashes reading absent keys in Get-ShopdbConfig (token-less mode) and Resolve-ShopdbPayloads (no-payload entries); validate the manifest response is JSON before overwriting the last-known-good cache - runner: pass the engine its required -InstallerRoot/-LogFile; create the log directory so enforce logging is not silently lost on a fresh kiosk - display scope: dispatcher writes an all-users Startup shortcut instead of Start-Process (SYSTEM cannot show a window in session 0), resolves the base URL from HKLM, and adds an always-on power/no-lock entry; tests updated for the 6-entry scope
This commit is contained in:
@@ -46,18 +46,36 @@ REPORT_SCOPE = 'geenforce.report'
|
||||
ALLOWED_CIDRS_SETTING = 'geenforce_allowed_cidrs'
|
||||
|
||||
|
||||
def _trusted_client_ip():
|
||||
"""The trustworthy caller IP for the AUTH allowlist.
|
||||
|
||||
Uses request.remote_addr, NOT the raw X-Forwarded-For header. Proxies APPEND
|
||||
to X-Forwarded-For, so its first hop is attacker-controlled: parsing it (as
|
||||
_client_ip does for rate-limiting) would let any caller send
|
||||
'X-Forwarded-For: <allowlisted-ip>' and bypass the token. remote_addr cannot
|
||||
be forged here - behind IIS the URL-Rewrite rule overwrites X-Forwarded-For
|
||||
with the real TCP peer and waitress (--trusted-proxy=127.0.0.1
|
||||
--trusted-proxy-headers=x-forwarded-for) derives remote_addr from it; a
|
||||
client hitting waitress directly is not a trusted proxy, so its remote_addr
|
||||
is its own real peer address. Either way remote_addr is the true client.
|
||||
"""
|
||||
return request.remote_addr or ''
|
||||
|
||||
|
||||
def _ip_allowlisted():
|
||||
"""True when the caller IP falls in the configured geenforce allowlist.
|
||||
|
||||
Lets vaulted fleet PCs reach the client endpoints without a per-PC token -
|
||||
network trust replaces the shared secret. Fails closed: an unparseable
|
||||
caller IP or malformed allowlist entry never matches. Empty setting = off.
|
||||
Uses the SPOOF-RESISTANT remote_addr (see _trusted_client_ip), never the raw
|
||||
X-Forwarded-For header.
|
||||
"""
|
||||
raw = (Setting.get(ALLOWED_CIDRS_SETTING) or '').strip()
|
||||
if not raw:
|
||||
return False
|
||||
try:
|
||||
ip = ipaddress.ip_address(_client_ip())
|
||||
ip = ipaddress.ip_address(_trusted_client_ip())
|
||||
except ValueError:
|
||||
return False
|
||||
for part in raw.split(','):
|
||||
|
||||
Reference in New Issue
Block a user