diff --git a/fn/common.php b/fn/common.php index 79db585..1b66bbb 100644 --- a/fn/common.php +++ b/fn/common.php @@ -136,3 +136,27 @@ function equalArrays($a, $b) { function linkToDocs($ref, $title) { return '' . $title . ''; } + +/* + This token authenticates the user to the server through a public communication (the DNS). + It is therefore also designed to keep private: + - the user's id + - that a same user used a token multiple times (by using a unique salt for each token) +*/ +define('SECRET_KEY_FILE', sys_get_temp_dir() . '/Niver.key'); +if (!file_exists(SECRET_KEY_FILE)) { + $original_umask = umask(0077); + file_put_contents(SECRET_KEY_FILE, random_bytes(32)); + umask($original_umask); +} +define('SECRET_KEY', file_get_contents(SECRET_KEY_FILE)); +function getAuthToken() { + $salt = bin2hex(random_bytes(4)); + $hash = hash_hmac('sha256', $salt . ($_SESSION['username'] ?? ''), SECRET_KEY); + return $salt . '-' . substr($hash, 0, 32); +} +function checkAuthToken($salt, $hash) { + $correctProof = substr(hash_hmac('sha256', $salt . $_SESSION['username'], SECRET_KEY), 0, 32); + if (hash_equals($correctProof, $hash) !== true) + output(403, 'Preuve incorrecte'); +} diff --git a/pages/ht/add-http-dns.php b/pages/ht/add-http-dns.php index 362b9bc..4fda659 100644 --- a/pages/ht/add-http-dns.php +++ b/pages/ht/add-http-dns.php @@ -16,16 +16,24 @@ if (processForm()) { $remoteAaaaRecords = dns_get_record($_POST['domain'], DNS_AAAA); if (is_array($remoteAaaaRecords) !== true) - output(403, 'Ce domaine n\'existe pas.'); + output(500, 'Erreur lors de la récupération de l\'enregistrement AAAA.'); if (equalArrays([CONF['ht']['ipv6_address']], array_column($remoteAaaaRecords, 'ipv6')) !== true) output(403, 'Ce domaine doit avoir pour unique enregistrement AAAA ' . CONF['ht']['ipv6_address'] . '.'); $remoteARecords = dns_get_record($_POST['domain'], DNS_A); if (is_array($remoteARecords) !== true) - output(403, 'Ce domaine n\'existe pas.'); + output(500, 'Erreur lors de la récupération de l\'enregistrement A.'); if (equalArrays([CONF['ht']['ipv4_address']], array_column($remoteARecords, 'ip')) !== true) output(403, 'Ce domaine doit avoir pour unique enregistrement A ' . CONF['ht']['ipv4_address'] . '.'); + $remoteTXTRecords = dns_get_record($_POST['domain'], DNS_TXT); + if (is_array($remoteTXTRecords) !== true) + output(500, 'Erreur lors de la récupération de l\'enregistrement TXT.'); + if (preg_match('/\nauth-owner=([0-9a-f]{8})-([0-9a-f]{32})\n/', "\n" . implode("\n", array_column($remoteTXTRecords, 'txt')) . "\n", $matches) !== 1) + output(403, 'Aucun enregistrement TXT au format correct trouvé.'); + + checkAuthToken($matches[1], $matches[2]); + rateLimit(); addSite($_SESSION['username'], $_POST['dir'], $_POST['domain'], "dns", "http"); @@ -57,6 +65,8 @@ if (processForm()) { output(200, 'Accès HTTP par domaine ajouté sur ce dossier !'); } +$proof = getAuthToken(); + ?>

@@ -64,19 +74,24 @@ if (processForm()) {

- Le domaine doit contenir ces enregistrements : -

-
AAAA
-
- -
-
A
-
- -
-
+ La présence des enregistrements ci-après sera vérifiée lors du traitement de ce formulaire.

+
+
AAAA
+
+ +
+
A
+
+ +
+
TXT
+
+ auth-owner= +
+
+


diff --git a/pages/ns/zone-add.php b/pages/ns/zone-add.php index 0bf62ee..8c9a04a 100644 --- a/pages/ns/zone-add.php +++ b/pages/ns/zone-add.php @@ -6,13 +6,17 @@ if (processForm()) { if (query('select', 'zones', ['zone' => $_POST['domain']], 'zone') !== []) output(403, 'Cette zone existe déjà sur ce service.'); - exec(CONF['ns']['kdig_path'] . " " . ltrim(strstr($_POST['domain'], '.'), '.') . " NS +short", $parentAuthoritatives); + exec(CONF['ns']['kdig_path'] . ' ' . ltrim(strstr($_POST['domain'], '.'), '.') . ' NS +short', $parentAuthoritatives); + if ($parentAuthoritatives === []) + output(403, 'Serveurs de noms de la zone parente introuvables'); foreach ($parentAuthoritatives as $parentAuthoritative) checkAbsoluteDomainFormat($parentAuthoritative); - exec(CONF['ns']['kdig_path'] . " " . $_POST['domain'] . " NS @" . $parentAuthoritatives[0], $results); - preg_match_all('/' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,8}[\t ]+IN[\t ]+NS[\t ]+(.+)\n/', implode("\n", $results), $matches); - if (equalArrays(CONF['ns']['servers'], $matches[1]) !== true) - output(403, 'Les serveurs ayant autorité dans cette zone indiqués par la zone parente ne sont pas ceux de Niver.'); + + exec(CONF['ns']['kdig_path'] . ' ' . $_POST['domain'] . " NS @" . $parentAuthoritatives[0], $results); + if (preg_match('/\n' . preg_quote($_POST['domain'], '/') . '[\t ]+[0-9]{1,8}[\t ]+IN[\t ]+NS[\t ]+([0-9a-f]{8})-([0-9a-f]{32})\.auth-owner.+\n/', implode("\n", $results), $matches) !== 1) + output(403, 'Enregistrement d\'authentification introuvable'); + + checkAuthToken($matches[1], $matches[2]); rateLimit(); @@ -38,10 +42,16 @@ if (processForm()) { output(200, 'La requête a été traitée.'); } +$proof = getAuthToken(); + ?>

- Le domaine doit avoir pour enregistrements NS : + Le domaine doit avoir un qui commence par .auth-owner lors du traitement de ce formulaire. +

+ +

+ La zone sera servie par ces serveurs de noms :