ipInNetwork(): Praefixlaenge pruefen statt ungeprueft uebernehmen

Die Laenge wurde mit intval() aus dem CIDR-String uebernommen. Bei einem
Tippfehler in LOCAL_NETWORKS lief die Funktion damit fail-open: "/-5" ergibt
intdiv(-5,8)=0 ganze Bytes und chr((0xFF << 13) & 0xFF)=Nullbyte, womit beide
maskierten Bytes gleich sind und jede Adresse in jedem Netz liegt. isLocal()
haette dann jede Anfrage aus dem Internet als lokal gewertet - und damit als
angemeldet, inklusive Freigabe der Passkey-Registrierung.

Die Laenge muss jetzt aus reinen Ziffern bestehen und darf die Adressbreite
nicht ueberschreiten; sonst liefert die Funktion false. "/-5", "/244", "/abc"
und "/" fallen damit durch, gueltige Angaben bleiben unveraendert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-28 16:14:25 +02:00
co-authored by Claude Opus 5
parent 16e236c7f8
commit dc85f33e9f
+14 -1
View File
@@ -20,7 +20,20 @@ function ipInNetwork($ip, $cidr)
if ($adresse === false || $netz === false || strlen($adresse) !== strlen($netz)) {
return false; // ungueltig oder verschiedene Adressfamilien
}
$bits = isset($teile[1]) ? intval($teile[1]) : strlen($adresse) * 8;
// Praefixlaenge streng pruefen. Ohne das macht ein Tippfehler in
// LOCAL_NETWORKS die Funktion fail-open: "/-5" etwa liefert eine
// Nullmaske, und dann liegt jede Adresse in jedem Netz.
if (isset($teile[1])) {
if (!ctype_digit($teile[1])) {
return false;
}
$bits = intval($teile[1]);
if ($bits > strlen($adresse) * 8) {
return false;
}
} else {
$bits = strlen($adresse) * 8;
}
$ganzeBytes = intdiv($bits, 8);
$restBits = $bits % 8;
if ($ganzeBytes > 0 && strncmp($adresse, $netz, $ganzeBytes) !== 0) {