feat: initial implementation of website integrity scanner

Python-Package zur unabhängigen Überwachung statischer Websites gegen
SEO-Spam und unbefugte Manipulationen. Läuft außerhalb des Hosters.

Kernfunktionen:
- Reiner Python-Crawler (bs4+lxml), kein wget
- Baseline-Management mit manuellem Freigabe-Workflow (niemals automatisch)
- Text-/Link-/Meta-Diff mit Risiko-Scoring (grün/gelb/rot)
- Hidden-Content-Erkennung (CSS inline, noscript, Kommentar-Links)
- Whitelist für externe Domains und interne Pfade
- E-Mail + Webhook Alarmierung
- CLI: init, crawl, check, scan, approve, report, status
- 79 Unit-Tests (pytest), alle grün

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Your Name 2026-06-12 00:51:41 +02:00
commit 98e8d11eb5
24 changed files with 4295 additions and 0 deletions

203
README.md Normal file
View file

@ -0,0 +1,203 @@
# Website Integrity Scanner
Unabhängiges Überwachungswerkzeug für statische Websites gegen SEO-Spam
und unbefugte Manipulationen. Läuft im Verantwortungsbereich des Betreibers,
nicht beim Webhoster.
## Schnellstart
```bash
cd integrity_scanner_fuer_statische_Webseiten
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
# 1. Erste Baseline anlegen
python -m scanner init
# 2. Ergebnis prüfen, dann freigeben
python -m scanner approve --all --note "Initiale Baseline nach Sichtprüfung"
# 3. Täglicher Betrieb (oder per Cron)
python -m scanner scan
```
---
## Subcommands
| Befehl | Funktion |
|---|---|
| `init` | Erstcrawl + Vorschau, kein Baseline-Update |
| `crawl` | Crawlt die Website, speichert Snapshot |
| `check` | Vergleicht letzten Snapshot mit Baseline |
| `scan` | `crawl` + `check` in einem (für Cron) |
| `approve --all` | Alle Snapshot-URLs als neue Baseline freigeben |
| `approve --url URL` | Einzelne URL freigeben |
| `approve --rebuild` | Gesamte Baseline ersetzen (nach großer Änderung) |
| `report` | Letzten Report anzeigen |
| `status` | Baseline-Datum, letzter Scan, Risiko-Level |
Alle Befehle akzeptieren `--config path/to/config.yaml` und `--verbose`.
---
## Workflow: Erstinitialisierung
```
python -m scanner init
```
Ausgabe zeigt:
- alle gefundenen internen URLs
- alle externen Links (mit Whitelist-Status)
- potenzielle Auffälligkeiten (Hidden Content, Meta-Refresh, ...)
**Wichtig**: Die Ausgabe manuell prüfen, bevor die Baseline gesetzt wird.
Insbesondere externe Links in `config/allowed_external.yaml` eintragen.
```
python -m scanner approve --all --note "Initiale Baseline, geprüft am $(date)"
```
---
## Workflow: Täglicher Betrieb (Cron)
```
python -m scanner scan
```
Exit-Codes:
- `0` = Grün (keine Auffälligkeiten)
- `1` = Gelb (Warnung, manuelle Prüfung empfohlen)
- `2` = Rot (Alarm, sofortige Prüfung notwendig)
---
## Workflow: Legitime Änderung freigeben
```bash
# 1. Scan durchgeführt, Warnung auf /impressum/
python -m scanner report # Report ansehen
python -m scanner approve --url https://bredelar.info/impressum/ --note "Impressum aktualisiert"
# 2. Oder alle Änderungen auf einmal (wenn alles geprüft)
python -m scanner approve --all --note "Redesign vom 2026-06-12 freigegeben"
# 3. Nach großem Redesign: komplette neue Baseline
python -m scanner approve --rebuild --note "Komplettes Redesign, alle Seiten neu"
```
---
## Workflow: Incident (Alarm)
1. Report lesen: `python -m scanner report`
2. Verdächtige URLs manuell im Browser prüfen
3. Quelltext der betroffenen Seiten ansehen (insb. `display:none`-Bereiche)
4. Dienstleister kontaktieren, Zugriff auf Hosting prüfen
5. Nach Bereinigung: `python -m scanner scan` — muss grün sein
6. Dann: `python -m scanner approve --rebuild --note "Nach Incident bereinigt"`
**Wichtig**: Niemals `approve` auf eine kompromittierte Seite anwenden.
---
## Cron-Setup
```cron
# Täglich 03:00 Uhr
0 3 * * * cd /opt/scanner && /opt/scanner/venv/bin/python -m scanner scan >> /opt/scanner/logs/cron.log 2>&1
```
Log-Rotation (`/etc/logrotate.d/scanner`):
```
/opt/scanner/logs/*.log {
daily
rotate 30
compress
missingok
notifempty
}
```
---
## Konfiguration
### E-Mail aktivieren
In `config.yaml`:
```yaml
alerting:
email:
enabled: true
smtp_host: mail.example.com
smtp_port: 587
smtp_user: scanner@example.com
smtp_password_env: SCANNER_SMTP_PASSWORD
from: scanner@bredelar.info
to:
- admin@bredelar.info
```
Passwort als Umgebungsvariable setzen (nicht in config.yaml):
```bash
export SCANNER_SMTP_PASSWORD="geheimesPasswort"
```
### Webhook aktivieren
```yaml
alerting:
webhook:
enabled: true
url: "https://hooks.slack.com/services/..."
```
### Externe Domains whitelisten
Nach dem ersten `init` alle legitimen externen Domains in
`config/allowed_external.yaml` eintragen:
```yaml
- fonts.googleapis.com
- maps.googleapis.com
```
---
## Verzeichnisstruktur
```
data/
baseline/ Aktuell freigegebene Referenz (NIEMALS automatisch aktualisiert)
manifest.json Wer/was/wann freigegeben hat
pages/ Pro URL eine JSON-Datei
snapshots/ Zeitgestempelte Crawl-Ergebnisse
YYYYMMDD_HHMMSS/
reports/ Generierte Reports (JSON + Markdown)
logs/ scanner.log
config/
allowed_external.yaml
allowed_paths.yaml
ignore_rules.yaml
```
---
## Tests
```bash
pytest tests/ -v
```
---
## Erweiterungen (optional, nicht implementiert)
- Ollama-Integration: Neue Textblöcke semantisch auf Spam-Kategorien prüfen
- Telegram-Bot: direkter Alert-Kanal
- Diff-Anzeige im Terminal: `python -m scanner report --diff-only`
- Automatische Archivierung alter Snapshots nach N Tagen