72 lines
2.9 KiB
PHP
72 lines
2.9 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
use Steuerkram\Models\Setting;
|
||
use Steuerkram\Services\SmtpMailer;
|
||
|
||
/**
|
||
* Test 69: SMTP-Header-/Kommando-Injection über mail_from_email verhindert (Fix #148).
|
||
*/
|
||
class MailFromEmailInjectionTest extends TestCase
|
||
{
|
||
protected string $testName = 'Test 69: mail_from_email – Validierung & SmtpMailer-Härtung';
|
||
|
||
public function run(): void
|
||
{
|
||
$before = Setting::get();
|
||
$base = array_merge($before, [
|
||
'firma' => $before['firma'] ?: 'Testfirma',
|
||
'strasse' => $before['strasse'] ?: 'Teststr. 1',
|
||
'plz' => $before['plz'] ?: '12345',
|
||
'ort' => $before['ort'] ?: 'Testort',
|
||
]);
|
||
|
||
// Gültige Adresse wird unverändert übernommen
|
||
Setting::update(array_merge($base, [
|
||
'mail_from_email' => 'rechnung@firma.example',
|
||
]));
|
||
$this->assertEquals('rechnung@firma.example', Setting::get()['mail_from_email'], 'Gültige Absenderadresse wird gespeichert');
|
||
|
||
// CRLF-Payload (SMTP-Kommando-Injection) wird beim Speichern verworfen, nicht nur bereinigt
|
||
Setting::update(array_merge($base, [
|
||
'mail_from_email' => "admin@firma.example>\r\nRCPT TO:<angreifer@evil.example>\r\nDATA",
|
||
]));
|
||
$stored = Setting::get()['mail_from_email'];
|
||
$this->assert(
|
||
!str_contains($stored, "\r") && !str_contains($stored, "\n"),
|
||
'Gespeicherte Absenderadresse enthält kein CR/LF'
|
||
);
|
||
$this->assertEquals('', $stored, 'Ungültige (CRLF-behaftete) Absenderadresse wird verworfen statt gespeichert');
|
||
|
||
// Andere ungültige Werte (kein E-Mail-Format) werden ebenfalls verworfen
|
||
Setting::update(array_merge($base, [
|
||
'mail_from_email' => 'keine-email-adresse',
|
||
]));
|
||
$this->assertEquals('', Setting::get()['mail_from_email'], 'Nicht-E-Mail-Wert wird verworfen');
|
||
|
||
// Ursprünglichen Zustand wiederherstellen
|
||
Setting::update(array_merge($base, [
|
||
'mail_from_email' => $before['mail_from_email'] ?? '',
|
||
]));
|
||
|
||
// Defense-in-depth: SmtpMailer::sanitizeAddress() entfernt CRLF selbst,
|
||
// falls eine mit CRLF behaftete Adresse trotzdem in den Mailer gelangt.
|
||
$mailer = new SmtpMailer(
|
||
host: '127.0.0.1',
|
||
port: 1,
|
||
encryption: 'none',
|
||
user: '',
|
||
pass: '',
|
||
fromEmail: 'absender@example.com',
|
||
fromName: 'Absender',
|
||
);
|
||
$ref = new \ReflectionMethod($mailer, 'sanitizeAddress');
|
||
$ref->setAccessible(true);
|
||
$result = $ref->invoke($mailer, "admin@firma.example>\r\nRCPT TO:<angreifer@evil.example>");
|
||
$this->assert(
|
||
!str_contains($result, "\r") && !str_contains($result, "\n"),
|
||
'sanitizeAddress() entfernt CR/LF aus der Absenderadresse'
|
||
);
|
||
}
|
||
}
|