From 5769f3fc889de8a345139f8847aae1897deb5bd6 Mon Sep 17 00:00:00 2001 From: Your Name Date: Fri, 12 Jun 2026 03:28:36 +0200 Subject: [PATCH] =?UTF-8?q?docs:=20Bedienungsanleitung=20hinzuf=C3=BCgen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Vollständige Bedienungsanleitung für den täglichen Betrieb, Erstinbetriebnahme, Alarm-Workflows, Cron-Setup, E-Mail-Konfiguration und Konfigurationsreferenz. Co-Authored-By: Claude Sonnet 4.6 --- BEDIENUNGSANLEITUNG.md | 542 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 542 insertions(+) create mode 100644 BEDIENUNGSANLEITUNG.md diff --git a/BEDIENUNGSANLEITUNG.md b/BEDIENUNGSANLEITUNG.md new file mode 100644 index 0000000..4a99f69 --- /dev/null +++ b/BEDIENUNGSANLEITUNG.md @@ -0,0 +1,542 @@ +# Bedienungsanleitung — Website Integrity Scanner + +Überwachungswerkzeug für die statische Website **bredelar.info** gegen SEO-Spam und +unbefugte Manipulationen. Der Scanner läuft lokal im Verantwortungsbereich des Betreibers. + +--- + +## Inhaltsverzeichnis + +1. [Grundprinzip](#1-grundprinzip) +2. [Voraussetzungen und Installation](#2-voraussetzungen-und-installation) +3. [Erstinbetriebnahme](#3-erstinbetriebnahme) +4. [Täglicher Betrieb](#4-täglicher-betrieb) +5. [Befehle im Überblick](#5-befehle-im-überblick) +6. [Ergebnis-Level und Exit-Codes](#6-ergebnis-level-und-exit-codes) +7. [Berichte lesen](#7-berichte-lesen) +8. [Änderungen freigeben (approve)](#8-änderungen-freigeben-approve) +9. [Vorgehen bei einem Alarm](#9-vorgehen-bei-einem-alarm) +10. [Automatisierung per Cron-Job](#10-automatisierung-per-cron-job) +11. [E-Mail-Benachrichtigung einrichten](#11-e-mail-benachrichtigung-einrichten) +12. [Konfigurationsreferenz](#12-konfigurationsreferenz) +13. [Externe Domains verwalten](#13-externe-domains-verwalten) +14. [Rausch-Unterdrückung konfigurieren](#14-rausch-unterdrückung-konfigurieren) +15. [Was der Scanner erkennt](#15-was-der-scanner-erkennt) +16. [Verzeichnisstruktur](#16-verzeichnisstruktur) + +--- + +## 1. Grundprinzip + +Der Scanner arbeitet nach dem **Baseline-Diff-Prinzip**: + +``` +Initiale Sichtprüfung → Baseline festlegen + ↓ + Täglicher Scan + ↓ + Aktueller Zustand ──vergleiche── genehmigte Baseline + ↓ + Abweichungen → Score → GREEN / YELLOW / RED +``` + +- Die **Baseline** ist ein einmal manuell geprüfter und freigegebener Referenzzustand. + Sie wird **niemals automatisch** aktualisiert. +- Jede Abweichung erhält Punkte. Der Gesamt-Score entscheidet über das Alarm-Level. +- Legitime Änderungen (z.B. neuer Artikel) müssen explizit per `approve` freigegeben werden. + +--- + +## 2. Voraussetzungen und Installation + +```bash +# Python 3.10 oder neuer erforderlich +python3 --version + +# Virtuelle Umgebung anlegen und aktivieren +cd /home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten +python3 -m venv venv +source venv/bin/activate + +# Abhängigkeiten installieren +pip install -r requirements.txt +``` + +Alle Befehle müssen aus dem Projektverzeichnis ausgeführt werden (dort liegt `config.yaml`). + +--- + +## 3. Erstinbetriebnahme + +### Schritt 1: Ersten Crawl durchführen + +```bash +python -m scanner init +``` + +Die Ausgabe zeigt: +- alle gefundenen internen URLs +- alle externen Domains (mit Hinweis, ob in der Whitelist) +- potenzielle Auffälligkeiten (Hidden Content, Meta-Refresh, verdächtige Scripts) +- Crawl-Fehler (Seiten, die nicht erreichbar waren) + +### Schritt 2: Ausgabe manuell prüfen + +Wichtig vor dem nächsten Schritt: +- Alle externen Domains prüfen. Legitime Domains in `config/allowed_external.yaml` eintragen + (siehe [Abschnitt 13](#13-externe-domains-verwalten)). +- Auffälligkeiten im Browser nachschauen. + +### Schritt 3: Baseline freigeben + +Nur wenn alles sauber ist: + +```bash +python -m scanner approve --all --note "Initiale Baseline, geprüft am $(date +%Y-%m-%d)" +``` + +Ab jetzt ist der tägliche Betrieb möglich. + +--- + +## 4. Täglicher Betrieb + +### Manueller Scan + +```bash +python -m scanner scan +``` + +Ergebnis erscheint direkt im Terminal. Der vollständige Report liegt in `reports/`. + +### Automatischer Scan (Cron) + +```bash +# Cron-Eintrag hinzufügen +crontab -e +``` + +Eintrag: +```cron +# Website-Scan täglich um 03:00 Uhr +0 3 * * * cd /home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten && /home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten/venv/bin/python -m scanner scan >> logs/cron.log 2>&1 +``` + +Der Exit-Code (0/1/2) ist für Cron-basierte Alarmierung nutzbar (z.B. mit `cronitor` oder +systemd-Timern mit `OnFailure=`). + +--- + +## 5. Befehle im Überblick + +Alle Befehle werden mit `python -m scanner ` aufgerufen. +Globale Optionen: `--config path/to/config.yaml`, `--verbose` (`-v`). + +| Befehl | Zweck | +|---|---| +| `init` | Erstcrawl, Ausgabe aller Funde, noch kein Baseline-Update | +| `crawl` | Crawlt die Website, speichert Snapshot (kein Vergleich) | +| `check` | Vergleicht letzten Snapshot mit Baseline, erstellt Report | +| `scan` | `crawl` + `check` in einem Schritt (für den Cron-Betrieb) | +| `approve --all` | Alle neuen Snapshot-URLs in die Baseline übernehmen | +| `approve --url URL` | Einzelne URL freigeben | +| `approve --rebuild` | Gesamte Baseline ersetzen (nach großem Redesign) | +| `report` | Letzten Report im Terminal anzeigen | +| `report --format json` | Letzten Report als JSON anzeigen | +| `status` | Baseline-Datum, letzter Scan, aktueller Risk-Level | + +### Beispiele + +```bash +# Einzelne Seite freigeben (z.B. nach Impressums-Update) +python -m scanner approve --url https://bredelar.info/impressum/ --note "Impressum aktualisiert Juni 2026" + +# Alle Änderungen auf einmal freigeben (nur nach vollständiger Prüfung!) +python -m scanner approve --all --note "Redesign vom 2026-06-12 freigegeben" + +# Baseline nach komplettem Umbau neu aufbauen +python -m scanner approve --rebuild --note "Komplettes Redesign v2, alle Seiten neu geprüft" + +# Bestimmten Snapshot freigeben (statt den neuesten) +python -m scanner approve --all --snapshot data/snapshots/20260612_030000 + +# Aktuellen Stand prüfen +python -m scanner status + +# Letzten Report anzeigen +python -m scanner report +``` + +--- + +## 6. Ergebnis-Level und Exit-Codes + +| Level | Score | Exit-Code | Bedeutung | +|---|---|---|---| +| **GREEN** | 0–19 | `0` | Keine Auffälligkeiten | +| **YELLOW** | 20–59 | `1` | Warnung — manuelle Prüfung empfohlen | +| **RED** | ≥ 60 | `2` | Alarm — sofortige Prüfung notwendig | + +Die Schwellenwerte sind in `config.yaml` unter `thresholds` anpassbar. + +--- + +## 7. Berichte lesen + +Reports liegen in `reports/YYYYMMDD_HHMMSS/` als `report.md` und `report.json`. + +```bash +# Neuesten Report im Terminal lesen +python -m scanner report + +# Direkt die Datei öffnen +ls reports/ +cat reports/20260612_030000/report.md +``` + +### Aufbau des Reports + +| Abschnitt | Inhalt | +|---|---| +| **Zusammenfassung** | Kennzahlen auf einen Blick | +| **Risikobewertung** | Alle Gründe für den Score (was hat wie viele Punkte ausgelöst) | +| **Neue externe Domains** | Domains, die bisher nicht in der Baseline waren | +| **Neue interne URLs** | Seiten, die neu dazugekommen sind | +| **Fehlende URLs** | Seiten, die in der Baseline stehen, jetzt aber nicht mehr gefunden wurden | +| **Geänderte Seiten** | Detailansicht: Textänderungen, Link-Diffs, Meta-Änderungen | +| **Kaputte Links** | `[NEU]` = noch nicht in Baseline, `[bekannt]` = schon bekannt, wird nicht bewertet | +| **Unerwartetes JSON-LD** | Strukturierte Daten mit unbekanntem `@type` | +| **Verdächtige Dateinamen** | Links auf Dateien mit Webshell-typischen Namen | +| **Whitelist-Verstösse** | Externe Domains, die nicht in `allowed_external.yaml` stehen | +| **Fehlende Security-Header** | Informativ (kein Score) — nur auf HTTP-200-Seiten | +| **Crawl-Fehler** | URLs, die der Crawler nicht laden konnte | +| **Nächste Schritte** | Abhängig vom Level: konkrete Handlungsempfehlungen | + +--- + +## 8. Änderungen freigeben (approve) + +Wann `approve` nötig ist: +- Nach einer legitimen Inhaltsänderung (neuer Artikel, aktualisiertes Impressum, ...) +- Nach einem Redesign +- Nach Bereinigung eines echten Angriffs + +### Einzelne URL freigeben + +Wenn nur eine bestimmte Seite geändert wurde: + +```bash +python -m scanner approve --url https://bredelar.info/veranstaltungen/ \ + --note "Veranstaltungskalender aktualisiert" +``` + +### Alle Änderungen freigeben + +Nach Prüfung aller markierten URLs: + +```bash +python -m scanner approve --all --note "Monatliches Update geprüft und freigegeben" +``` + +**Achtung**: `--all` übernimmt alles aus dem letzten Snapshot. Nur anwenden, wenn jede +gemeldete Änderung manuell gesichtet wurde. + +### Komplette Baseline neu aufbauen + +Nach einem großen Redesign oder nach Bereinigung eines Angriffs: + +```bash +python -m scanner approve --rebuild --note "Nach Angriff bereinigt, neues Redesign" +``` + +`--rebuild` ersetzt die gesamte bestehende Baseline durch den aktuellen Snapshot. + +--- + +## 9. Vorgehen bei einem Alarm + +### YELLOW — Warnung + +1. Report lesen: `python -m scanner report` +2. Markierte URLs im Browser aufrufen und Quelltext prüfen +3. Ist die Änderung legitim? + - Ja: `python -m scanner approve --url --note "Grund"` + - Nein: Abschnitt [Angriff](#angriff) lesen + +### RED — Alarm + +Der Score ist ≥ 60. Typische Auslöser: neue externe Domain (50 Pkt.) + Hidden Content +(40 Pkt.), Webshell-Dateiname (60 Pkt.), Meta-Refresh (40 Pkt.). + +#### Angriff + +1. **Nicht sofort approve aufrufen** — das würde den kompromittierten Zustand als neue + Baseline festschreiben. +2. Report sichern: `cp -r reports/$(ls reports/ | tail -1) ~/alarm-$(date +%Y%m%d)/` +3. Website im Browser aufrufen und nach sichtbaren Fremdinhalten suchen. +4. Quelltext der betroffenen Seiten prüfen (insbesondere `display:none`-Bereiche). +5. Hoster kontaktieren, SSH-/FTP-Zugriffslogs prüfen. +6. Dateien mit Backup vergleichen (diff oder rsync --dry-run). +7. Nach vollständiger Bereinigung: + ```bash + python -m scanner scan # muss GREEN ergeben + python -m scanner approve --rebuild --note "Nach Angriff bereinigt $(date +%Y-%m-%d)" + ``` + +--- + +## 10. Automatisierung per Cron-Job + +### Cron-Eintrag + +```bash +crontab -e +``` + +```cron +# Website-Scan täglich um 03:00 Uhr +0 3 * * * cd /home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten && /home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten/venv/bin/python -m scanner scan >> logs/cron.log 2>&1 +``` + +### Log prüfen + +```bash +tail -50 logs/cron.log +tail -f logs/scanner.log # detaillierteres Log des Scanners selbst +``` + +### Log-Rotation (optional) + +Datei `/etc/logrotate.d/integrity-scanner`: +``` +/home/dschlueter/Python_Programs/integrity_scanner_fuer_statische_Webseiten/logs/*.log { + daily + rotate 30 + compress + missingok + notifempty +} +``` + +--- + +## 11. E-Mail-Benachrichtigung einrichten + +### config.yaml anpassen + +```yaml +alerting: + min_level: "yellow" # oder "red" — nur bei rotem Alarm mailen + email: + enabled: true + smtp_host: "mail.linix.de" # SMTP-Server des Providers + smtp_port: 587 + smtp_tls: true + smtp_user: "scanner@linix.de" + smtp_password_env: "SCANNER_SMTP_PASSWORD" + from: "scanner@bredelar.info" + to: + - "dieter.schlueter@linix.de" +``` + +### Passwort als Umgebungsvariable setzen + +**Niemals** das Passwort direkt in `config.yaml` eintragen. Stattdessen: + +```bash +# Temporär (bis zum nächsten Login) +export SCANNER_SMTP_PASSWORD="geheimesPasswort" + +# Dauerhaft in ~/.bashrc oder ~/.profile +echo 'export SCANNER_SMTP_PASSWORD="geheimesPasswort"' >> ~/.bashrc +``` + +Für den Cron-Job die Variable in der Crontab oder in `/etc/environment` setzen: +```cron +SCANNER_SMTP_PASSWORD=geheimesPasswort +0 3 * * * cd /home/dschlueter/... +``` + +--- + +## 12. Konfigurationsreferenz + +Alle Einstellungen in `config.yaml`. Fehlende Werte werden aus den Defaults übernommen. + +### Kern-Einstellungen + +| Schlüssel | Standard | Bedeutung | +|---|---|---| +| `target` | — | Zu überwachende URL (Pflicht) | +| `user_agent` | `integrity-scanner/1.0` | HTTP User-Agent | +| `request_timeout` | `20` | Timeout pro Seite in Sekunden | + +### Crawl-Einstellungen (`crawl:`) + +| Schlüssel | Standard | Bedeutung | +|---|---|---| +| `max_pages` | `200` | Maximale Anzahl gecrawlter Seiten | +| `delay_seconds` | `1.0` | Pause zwischen Requests (Server-Schonung) | +| `skip_extensions` | `.jpg`, `.pdf` etc. | Dateitypen, die nicht gecrawlt werden | + +### Score-Gewichte (`scoring:`) + +| Ereignis | Standard-Punkte | +|---|---| +| Verdächtiger Dateiname (Webshell) | 60 | +| Neue externe Domain | 50 | +| Hidden Content (CSS-verstecktes Element mit Links/Text) | 40 | +| Meta-Refresh | 40 | +| Unerwartete Canonical-URL | 35 | +| Unerwartetes JSON-LD `@type` | 35 | +| Neue interne URL | 30 | +| Neues verdächtiges Inline-Script | 30 | +| Link in HTML-Kommentar | 25 | +| Großer Textblock (>200 Zeichen) | 20 | +| Fehlende interne URL | 20 | +| Neuer kaputte Link (4xx/5xx, nicht in Baseline) | 20 | + +Alle Werte sind in `config.yaml` unter `scoring:` anpassbar. + +### Alarm-Schwellen (`thresholds:`) + +```yaml +thresholds: + yellow: 20 # ab hier: YELLOW + red: 60 # ab hier: RED + large_text_block_chars: 200 # ab dieser Zeichenanzahl gilt ein Textblock als "groß" +``` + +### Erlaubte JSON-LD-Typen (`allowed_jsonld_types:`) + +Alle `@type`-Werte, die in den strukturierten Daten der Website vorkommen dürfen. +Unbekannte Typen lösen einen Fund aus (35 Punkte). Aktuell konfiguriert: +`Organization`, `WebSite`, `WebPage`, `Article`, `BreadcrumbList`, `LocalBusiness`, +`Event`, `FAQPage` u.a. + +### Security-Header (`security_headers:`) + +Liste der Header, die auf jeder Seite erwartet werden. Fehlende Header werden im Report +gemeldet, aber **nicht** bewertet (kein Score-Einfluss). + +--- + +## 13. Externe Domains verwalten + +Datei: `config/allowed_external.yaml` + +```yaml +# Legitime externe Domains — eine pro Zeile +- fonts.googleapis.com +- www.kloster-bredelar.de +``` + +Neue externe Domain erscheint im Scanner: +1. Domain im Browser prüfen — gehört sie zur Website? +2. Wenn legitim: in `config/allowed_external.yaml` eintragen +3. `python -m scanner approve --url ` oder `--all` + +Wenn eine Domain **nicht** in der Liste steht, löst jedes Vorkommen 50 Punkte aus +(YELLOW-Alarm, bei weiteren Funden RED). + +--- + +## 14. Rausch-Unterdrückung konfigurieren + +Manche Inhalte ändern sich automatisch (Datumsangaben, Zeitstempel) und würden sonst +bei jedem Scan einen Fund auslösen. Zwei Mechanismen: + +### CSS-Selektoren ignorieren (`ignore_selectors:`) + +Elemente werden vor dem Diff vollständig aus dem DOM entfernt: + +```yaml +normalization: + ignore_selectors: + - "#last-modified" + - ".timestamp" + - ".cookie-banner" +``` + +Datei: direkt in `config.yaml` oder in `config/ignore_rules.yaml` (kommentierte Beispiele +dort vorhanden). + +### Text-Muster ignorieren (`ignore_patterns:`) + +Reguläre Ausdrücke, die im normalisierten Text durch `[IGNORED]` ersetzt werden: + +```yaml +normalization: + ignore_patterns: + - '\b\d{1,2}\.\s*(?:Januar|Februar|März|April|Mai|Juni|Juli|August|September|Oktober|November|Dezember)\s+\d{4}\b' + - '\b\d{1,2}\.\d{1,2}\.\d{4}\b' + - 'Stand:\s+\S+' +``` + +--- + +## 15. Was der Scanner erkennt + +### Erkennt der Scanner ... + +| Prüfung | Erkannt? | Anmerkung | +|---|---|---| +| Neuen Text auf einer Seite | Ja | Ab 200 Zeichen bewertet | +| Versteckten Text (CSS display:none etc.) | Ja | 40 Punkte | +| Neue externe Domain | Ja | 50 Punkte | +| Meta-Refresh-Weiterleitung | Ja | 40 Punkte | +| Webshell-Dateien (shell.php, c99 etc.) | Ja | 60 Punkte | +| Links in HTML-Kommentaren | Ja | 25 Punkte | +| Geänderte Canonical-URL | Ja | 35 Punkte | +| Unbekanntes JSON-LD `@type` | Ja | 35 Punkte | +| `eval()`, `atob()`, `XMLHttpRequest` in Scripts | Ja | 30 Punkte | +| Kaputte interne Links (neu) | Ja | 20 Punkte | +| Kaputte interne Links (bekannt) | Ja, informativ | Kein Score | +| Fehlende Security-Header | Ja, informativ | Kein Score | +| Kaputte **externe** Links | Nein | Nur ob Domain neu ist | +| Veränderungen in Bilddateien | Nein | Nur Dateiname/URL | +| Serverseitige Code-Änderungen | Nein | Nur sichtbare HTML-Ausgabe | + +### Grenzen des Scanners + +- Er prüft nur, was der Crawler als HTML-Seite sieht. Serverseitig eingeschleuster Code, + der nur unter bestimmten Bedingungen aktiv wird (z.B. nur für Suchmaschinen-Bots), + wird möglicherweise nicht erkannt. +- Bilder und andere Binärdateien werden nicht auf Inhalt geprüft. +- Externe Links werden nur auf Neuheit geprüft, nicht auf Erreichbarkeit. + +--- + +## 16. Verzeichnisstruktur + +``` +config.yaml Hauptkonfiguration +config/ + allowed_external.yaml Whitelist erlaubter externer Domains + ignore_rules.yaml Kommentierte Beispiele für Rausch-Unterdrückung +data/ + baseline/ Freigegebene Referenz (NIEMALS automatisch geändert) + manifest.json Wer/was/wann freigegeben hat + pages/ Pro URL eine JSON-Datei (16-stelliger Hex-Name) + snapshots/ Ein Verzeichnis pro Crawl-Durchlauf + YYYYMMDD_HHMMSS/ + manifest.json Zeitstempel, Seitenzahl, Fehler + pages/ Extrahierte Seiten-Daten +logs/ + scanner.log Detailliertes Laufzeit-Log + cron.log Ausgabe der Cron-Ausführungen +reports/ + YYYYMMDD_HHMMSS/ + report.md Menschenlesbarer Report + report.json Maschinenlesbarer Report (für spätere Auswertung) +scanner/ Python-Paket (Quellcode) +tests/ Automatisierte Tests +``` + +### Tests ausführen + +```bash +pytest tests/ -v # alle Tests +pytest tests/test_differ.py -v # einzelnes Testmodul +pytest tests/test_differ.py::TestScoreDiff::test_green_for_no_changes -v # einzelner Test +```