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:
commit
98e8d11eb5
24 changed files with 4295 additions and 0 deletions
203
README.md
Normal file
203
README.md
Normal 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
|
||||
Loading…
Add table
Add a link
Reference in a new issue