542 lines
17 KiB
Markdown
542 lines
17 KiB
Markdown
|
|
# 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 <befehl>` 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 <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 <betroffene-Seite>` 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
|
|||
|
|
```
|