clusev/app/Support/Ssh/VerifiesHostKey.php

39 lines
1.1 KiB
PHP

<?php
namespace App\Support\Ssh;
use App\Models\Server;
use phpseclib3\Net\SSH2;
use RuntimeException;
/**
* TOFU (trust-on-first-use) host-key pinning. phpseclib verifies the key-exchange
* signature but does NOT pin the server's host key, so a MITM presenting its own
* valid key would be accepted. We record the host key on first connect and refuse
* the connection on any later mismatch.
*/
trait VerifiesHostKey
{
private function verifyHostKey(SSH2 $conn, Server $server): void
{
$hostKey = $conn->getServerPublicHostKey();
if ($hostKey === false) {
throw new RuntimeException("Host-Key von {$server->name} ({$server->ip}) nicht lesbar — Verbindung abgebrochen.");
}
$known = (string) ($server->ssh_host_key ?? '');
if ($known !== '') {
if (! hash_equals($known, $hostKey)) {
throw new RuntimeException("Host-Key-Mismatch fuer {$server->name} ({$server->ip}) — moegliches MITM. Verbindung abgebrochen.");
}
return;
}
// trust on first use
$server->forceFill(['ssh_host_key' => $hostKey])->save();
}
}