feat(domains): Pruefung von DNS, Zuordnung und Zertifikat
Eine reine DNS-Pruefung sagt nichts darueber aus, ob der Webserver die Domain auch dem richtigen Verzeichnis zuordnet - genau das ist der haeufigste Fehler. Die Pruefung ruft die Domain deshalb von aussen auf einen signierten Endpunkt auf. Kommt der Aufruf mit gueltigem Token an, ist die ganze Kette bewiesen, denn nur diese Installation kann ein solches Token erzeugen. Erkannt und benannt werden: fehlender DNS-Eintrag, Domain-Weiterleitung des Registrars, falsches Verzeichnis, ungueltiges Zertifikat. Link-lokale Adressen werden nicht abgerufen - dort liegen bei Cloud- Anbietern die Metadaten-Dienste.
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Support;
|
||||
|
||||
/**
|
||||
* Kurzlebiges, signiertes Token fuer die Domain-Pruefung.
|
||||
*
|
||||
* Die Pruefung ruft die zu testende Domain von aussen auf. Der dafuer
|
||||
* noetige Endpunkt muss ohne Login erreichbar sein - deshalb ist er nur
|
||||
* mit einem gueltigen Token ansprechbar und antwortet sonst mit 404.
|
||||
*
|
||||
* Das Token ist zustandslos (HMAC ueber den Zeitstempel), es muss also
|
||||
* nichts zwischengespeichert werden. Kommt der Aufruf mit einem
|
||||
* gueltigen Token an, ist damit zugleich bewiesen, dass er bei DIESER
|
||||
* Installation gelandet ist - nur sie kennt das Geheimnis.
|
||||
*/
|
||||
final class CheckToken
|
||||
{
|
||||
/** Gueltigkeitsdauer in Sekunden. */
|
||||
public const LIFETIME = 180;
|
||||
|
||||
public static function create(string $secret, ?int $now = null): string
|
||||
{
|
||||
$timestamp = (string) ($now ?? time());
|
||||
|
||||
return $timestamp . '.' . hash_hmac('sha256', $timestamp, $secret);
|
||||
}
|
||||
|
||||
public static function isValid(string $token, string $secret, ?int $now = null): bool
|
||||
{
|
||||
$parts = explode('.', $token, 2);
|
||||
if (count($parts) !== 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
[$timestamp, $signature] = $parts;
|
||||
|
||||
if ($timestamp === '' || !ctype_digit($timestamp)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (abs(($now ?? time()) - (int) $timestamp) > self::LIFETIME) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hash_equals(hash_hmac('sha256', $timestamp, $secret), $signature);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user