Harden KantSites after the security review
- The installer only opens with a per-installation key that install.php creates and shows; the key is deleted with the first account. - Lock files keep .env, the database, backups and logs out of reach when a domain points at the project folder instead of public/. - Linked sections render by their own schema version, so an old section cannot carry unfiltered HTML into a newer page. - Editors no longer move, trash or change areas and post data of published pages; a scheduled publication goes live with the revision that was scheduled (migration 20261012000100). - Form stamps are bound to their form, IPv6 senders count per /64, and a flood per form or overall stops storing with a visible message. - The consent redirect rejects control characters, update targets must look like 1.2.3, and own CSS cannot reach outside its block. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
14e7a3b310
commit
ad7c333215
43 files changed
+810
-53
No files matched your search
@@ -12,6 +12,7 @@ use App\Domain\CmsUser;
|
||||
use App\Domain\InvalidPage;
|
||||
use App\Infrastructure\ConnectionFactory;
|
||||
use App\Ops\Installation;
|
||||
use App\Ops\Protection;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
@@ -48,6 +49,38 @@ final class InstallationTest extends TestCase
|
||||
$this->installation = $this->make();
|
||||
}
|
||||
|
||||
public function testMissingLockFilesAreAddedButAnOwnRootFileStays(): void
|
||||
{
|
||||
// var/ gibt es nicht im Archiv, also legt die Website die Sperrdatei selbst an (ADR 116).
|
||||
mkdir($this->root.'/config/schutz', 0o775, true);
|
||||
mkdir($this->root.'/vendor', 0o775, true);
|
||||
foreach (['sperren', 'stamm'] as $name) {
|
||||
copy(\dirname(__DIR__).'/config/schutz/'.$name.'.htaccess', $this->root.'/config/schutz/'.$name.'.htaccess');
|
||||
}
|
||||
file_put_contents($this->root.'/.htaccess', '# eigene Regeln
|
||||
');
|
||||
Protection::reset();
|
||||
Protection::ensure($this->root);
|
||||
self::assertStringContainsString('Require all denied', (string) file_get_contents($this->root.'/var/.htaccess'));
|
||||
self::assertStringContainsString('Require all denied', (string) file_get_contents($this->root.'/vendor/.htaccess'));
|
||||
self::assertSame('# eigene Regeln
|
||||
', file_get_contents($this->root.'/.htaccess'), 'Eine eigene Datei im Projektstamm bleibt.');
|
||||
Protection::reset();
|
||||
}
|
||||
|
||||
public function testTheInstallKeyIsCreatedOnceAndCheckedStrictly(): void
|
||||
{
|
||||
$key = $this->installation->installKey();
|
||||
self::assertMatchesRegularExpression('/^[a-f0-9]{32}$/', $key);
|
||||
self::assertSame($key, $this->installation->installKey(), 'Einmal angelegt, bleibt er.');
|
||||
self::assertTrue($this->installation->acceptsKey(' '.strtoupper($key).' '), 'Abgetippt mit Leerzeichen und Großbuchstaben zählt.');
|
||||
self::assertFalse($this->installation->acceptsKey(substr($key, 0, 31)));
|
||||
self::assertFalse($this->installation->acceptsKey(''));
|
||||
self::assertTrue($this->installation->acceptsProof($this->installation->keyProof()));
|
||||
self::assertFalse($this->installation->acceptsProof(''));
|
||||
self::assertFalse($this->installation->acceptsProof($key));
|
||||
}
|
||||
|
||||
protected function tearDown(): void
|
||||
{
|
||||
$this->db->close();
|
||||
|
||||
Reference in new issue
Block a user