| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/clients/client2/web21/web/api/v1/ |
Upload File : |
<?php
/**
* Mailserver- & E-Mail-Sicherheitscheck → GET /api/v1/mailsec.php?domain=example.com
*
* MX, SPF (+ Offenheit), DMARC (+ Policy), DKIM-Hinweis, MTA-STS, TLS-RPT, BIMI, DNSSEC.
*
* @package SafeMyIdent\Api
*/
declare(strict_types=1);
require __DIR__ . '/../lib/boot2.php';
require_once __DIR__ . '/../lib/rdap.php';
if (!smi_module_on('mail')) {
smi_json_error('Mail-Modul ist deaktiviert.', 403);
}
$domain = smi_valid_domain((string) ($_GET['domain'] ?? ''));
if ($domain === null) {
smi_json_error('Bitte eine gültige Domain angeben.', 422);
}
$cacheKey = 'mailsec|' . $domain;
$hit = smi_cache_get($cacheKey);
if ($hit !== null) {
smi_json_ok($hit, true);
}
$findTxt = static function (array $list, string $prefix): string {
foreach ($list as $t) { if (stripos($t, $prefix) === 0) { return $t; } }
return '';
};
// Gängige DKIM-Selektoren (werden alle auf einmal geprüft).
$dkimSelectors = ['default', 'google', 'selector1', 'selector2', 'k1', 'mail', 's1', 's2', 'dkim', 'mandrill', 'mxvault', 'zoho', 'protonmail', 'fm1'];
// ALLE benötigten Abfragen sammeln und in EINEM Batch (Gateway) auflösen.
$txtNames = array_merge(
[$domain, '_dmarc.' . $domain, '_mta-sts.' . $domain, '_smtp._tls.' . $domain, 'default._bimi.' . $domain],
array_map(static fn ($s) => $s . '._domainkey.' . $domain, $dkimSelectors)
);
$queries = [['name' => $domain, 'type' => 'MX']];
foreach ($txtNames as $n) { $queries[] = ['name' => $n, 'type' => 'TXT']; }
$res = smi_dns_many($queries);
$txtMap = [];
foreach ($txtNames as $k => $n) {
$strings = [];
foreach ((array) ($res[$k + 1] ?? []) as $r) {
if (!empty($r['txt'])) { $strings[] = (string) $r['txt']; }
elseif (!empty($r['entries']) && is_array($r['entries'])) { $strings[] = implode('', $r['entries']); }
}
$txtMap[$n] = $strings;
}
$txt = static function (string $name) use ($txtMap): array { return $txtMap[$name] ?? []; };
// MX (aus dem Batch) + Erreichbarkeit prüfen.
$mx = [];
foreach ((array) ($res[0] ?? []) as $r) {
if (!empty($r['target'])) {
$host = strtolower($r['target']);
$ips = smi_resolve_public_ips($host);
$mx[] = ['host' => $host, 'pri' => $r['pri'] ?? null, 'resolves' => !empty($ips['all'])];
}
}
usort($mx, static fn ($a, $b) => ($a['pri'] ?? 999) <=> ($b['pri'] ?? 999));
// SPF.
$spf = $findTxt($txt($domain), 'v=spf1');
$spfOpen = $spf !== '' && (bool) preg_match('/[\s]\+?all\b/i', $spf) && !preg_match('/[~\-]all\b/i', $spf);
// DMARC.
$dmarc = $findTxt($txt('_dmarc.' . $domain), 'v=DMARC1');
$dmarcPolicy = '';
if ($dmarc !== '' && preg_match('/\bp\s*=\s*([a-z]+)/i', $dmarc, $m)) {
$dmarcPolicy = strtolower($m[1]);
}
// DKIM-Hinweis (Selektoren wurden bereits mit-abgefragt).
$dkimFound = '';
foreach ($dkimSelectors as $sel) {
$rec = $findTxt($txt($sel . '._domainkey.' . $domain), 'v=DKIM1');
if ($rec === '') {
// Manche liefern ohne v=DKIM1, aber mit p=.
foreach ($txt($sel . '._domainkey.' . $domain) as $t) {
if (stripos($t, 'p=') !== false) { $rec = $t; break; }
}
}
if ($rec !== '') { $dkimFound = $sel; break; }
}
// MTA-STS, TLS-RPT, BIMI.
$mtaSts = $findTxt($txt('_mta-sts.' . $domain), 'v=STSv1');
$tlsRpt = $findTxt($txt('_smtp._tls.' . $domain), 'v=TLSRPTv1');
$bimi = $findTxt($txt('default._bimi.' . $domain), 'v=BIMI1');
// DNSSEC (RDAP).
$dnssec = null;
if (smi_module_on('rdap')) {
$rd = smi_rdap_domain($domain);
$dnssec = $rd['dnssec'];
}
// Bewertung + Empfehlungen.
$warn = [];
$hasMx = count($mx) > 0;
if (!$hasMx) {
$warn[] = ['level' => 'info', 'text' => 'Kein MX-Record gefunden – diese Domain empfängt vermutlich keine E-Mails.'];
} else {
if ($spf === '') { $warn[] = ['level' => 'error', 'text' => 'Kein SPF-Record: Absender-Fälschung ist leichter möglich.']; }
if ($spfOpen) { $warn[] = ['level' => 'warn', 'text' => 'SPF endet auf „+all“ und ist damit wirkungslos (zu offen).']; }
if ($dmarc === '') { $warn[] = ['level' => 'error', 'text' => 'Kein DMARC-Record: keine Richtlinie gegen Spoofing.']; }
elseif ($dmarcPolicy === 'none') { $warn[] = ['level' => 'warn', 'text' => 'DMARC-Policy „none“ – es wird nur überwacht, nicht durchgesetzt.']; }
if ($dkimFound === '') { $warn[] = ['level' => 'info', 'text' => 'Kein DKIM über gängige Selektoren gefunden (kann trotzdem vorhanden sein).']; }
if ($mtaSts === '') { $warn[] = ['level' => 'info', 'text' => 'Kein MTA-STS – TLS-Transportverschlüsselung wird nicht erzwungen.']; }
}
$out = [
'domain' => $domain,
'has_mx' => $hasMx,
'mx' => $mx,
'spf' => ['present' => $spf !== '', 'record' => $spf, 'too_open' => $spfOpen],
'dmarc' => ['present' => $dmarc !== '', 'record' => $dmarc, 'policy' => $dmarcPolicy],
'dkim' => ['found' => $dkimFound !== '', 'selector' => $dkimFound],
'mta_sts' => ['present' => $mtaSts !== '', 'record' => $mtaSts],
'tls_rpt' => ['present' => $tlsRpt !== '', 'record' => $tlsRpt],
'bimi' => ['present' => $bimi !== '', 'record' => $bimi],
'dnssec' => $dnssec,
'warnings' => $warn,
];
smi_cache_set($cacheKey, $out, (int) ($smi_cfg['cache_ttl'] ?? 900));
smi_json_ok($out);