73 lines
3 KiB
PHP
73 lines
3 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
/**
|
||
* Test 84: Reflektiertes XSS über kategorie_kontonummer/zahlungs_kontonummer
|
||
* bei der Buchungserfassung (BookingController::store()) ist geschlossen.
|
||
*/
|
||
class BookingStoreReflectedXssTest extends TestCase
|
||
{
|
||
protected string $testName = 'Test 84: Kein reflektiertes XSS über Kontonummer-Freitextfeld bei Buchungserfassung';
|
||
|
||
public function run(): void
|
||
{
|
||
$datum = date('Y-m-d');
|
||
$belegNr = 'XSS-KTO-' . uniqid();
|
||
|
||
$belegId = \Steuerkram\Models\Beleg::create([
|
||
'beleg_nr' => $belegNr,
|
||
'filename' => 'xss-test.pdf',
|
||
'storage_path' => '',
|
||
'mime_type' => 'application/pdf',
|
||
'file_hash' => hash('sha256', $belegNr),
|
||
'beleg_datum' => $datum,
|
||
'belegtyp' => 'Eingangsrechnung',
|
||
]);
|
||
$this->assertGreaterThan(0, $belegId, 'Beleg angelegt');
|
||
|
||
$payload = '<script>alert(document.cookie)</script>';
|
||
|
||
// Nachbau der Fehlerauflösung aus BookingController::store() (Zeile 100-105):
|
||
// eine nicht auflösbare Freitext-Kontonummer landet unescaped in $errors.
|
||
$errors = [
|
||
'kategorie_konto_id' => "Kontonummer '$payload' nicht gefunden.",
|
||
];
|
||
|
||
// BookingController::renderBelegDetail() nur bis zum Content-Fragment
|
||
// nachgebaut (belege/detail.php), ohne layout/base.php – ein zweiter
|
||
// voller Seiten-Render im selben Testlauf würde an der Funktions-
|
||
// deklaration in layout/nav.php scheitern (siehe Test 65).
|
||
$beleg = \Steuerkram\Models\Beleg::find($belegId);
|
||
$accounts = \Steuerkram\Models\Account::all(['aktiv' => 1]);
|
||
|
||
$controller = new \Steuerkram\Controllers\BookingController();
|
||
$renderView = new \ReflectionMethod($controller, 'renderView');
|
||
$renderView->setAccessible(true);
|
||
$html = $renderView->invoke($controller, 'belege/detail', [
|
||
'beleg' => $beleg,
|
||
'bookings' => \Steuerkram\Models\Booking::forBeleg($belegId),
|
||
'integrity' => \Steuerkram\Models\Beleg::verifyIntegrity($belegId),
|
||
'accounts' => $accounts,
|
||
'assets' => \Steuerkram\Models\Asset::all(),
|
||
'formErrors' => $errors,
|
||
'formData' => [],
|
||
'bankTx' => null,
|
||
'bankTxBrutto' => 0.0,
|
||
'linkedBankTx' => null,
|
||
]);
|
||
|
||
$this->assert(
|
||
!str_contains($html, $payload),
|
||
'Roher <script>-Payload aus kategorie_kontonummer erscheint nicht unescaped in der Ausgabe'
|
||
);
|
||
$this->assert(
|
||
!str_contains($html, '<script>alert(document.cookie)'),
|
||
'Kein ausführbares <script>-Tag in der Ausgabe (auch nicht durch Groß-/Kleinschreibung o.ä. verschleiert)'
|
||
);
|
||
$this->assert(
|
||
str_contains($html, htmlspecialchars($payload, ENT_QUOTES, 'UTF-8')),
|
||
'Escapte Version der Kontonummer erscheint in der Fehlermeldung (Kontonummer wurde nicht gefunden)'
|
||
);
|
||
}
|
||
}
|