Doku
Monitoring und Änderungsalarme
AppSafe vergleicht jeden Scan einer verifizierten Website mit dem vorherigen und sagt dir, was sich geändert hat. Mit geplanten Scans oder Re-Scans bei Deployment wird daraus ein laufendes Monitoring mit Alarmen per E-Mail, Slack, Discord oder signiertem Webhook.
Änderungsalarme sind in den Tarifen Pro, Agency und Team enthalten. Geplante Scans laufen bei Pro und Agency täglich oder wöchentlich, bei Team stündlich.
Was AppSafe vergleicht
- Neue und behobene Befunde.
- Security-Header, die hinzugefügt, entfernt oder abgeschwächt wurden (zum Beispiel eine entfernte Content-Security-Policy oder ein kürzeres HSTS max-age).
- Austausch des TLS-Zertifikats sowie Warnungen 14 und 3 Tage vor Ablauf des Zertifikats.
- Neue Drittanbieter-Skriptdomains und externe Skripte ohne Subresource Integrity.
- Neue Subdomains deiner Domain in den Certificate-Transparency-Logs (crt.sh) sowie Subdomains, deren CNAME auf eine gelöschte Ressource bei einem Hosting-Dienst zeigt. Dafür werden nur passive DNS-Abfragen verwendet.
- Änderungen an SPF-, DMARC-, CAA- und MX-Records.
Alarme werden bei geplanten Scans und Scans nach Deployments gesendet, einmal pro Problem: Ein Problem, das unverändert bleibt, löst beim nächsten Scan keinen erneuten Alarm aus. Verschwindet es und tritt wieder auf, wirst du erneut alarmiert.
Alarme einrichten
Öffne eine verifizierte Website in deinem Dashboard und füge unter Monitoring & Alarme Kanäle hinzu. Jeder Kanal hat einen Mindest-Schweregrad und eine Schaltfläche Testalarm senden.
- E-Mail: Eine beliebige E-Mail-Adresse. Alarme werden in der Sprache deines Kontos verfasst.
- Slack: Eine Incoming-Webhook-URL aus einer Slack-App (https://hooks.slack.com/services/…).
- Discord: Eine Kanal-Webhook-URL (Servereinstellungen → Integrationen → Webhooks).
- Webhook: Ein beliebiger https-Endpunkt. AppSafe sendet per POST den unten gezeigten JSON-Payload, signiert mit einem Secret, das beim Anlegen des Kanals einmal angezeigt wird.
Webhook-Payload
Generische Webhooks erhalten dieses JSON (Content-Type: application/json). Testalarme verwenden das Event monitoring.test, und scan ist null.
{
"event": "monitoring.changes",
"deliveryId": "5f2c9a0e41b7d3a8c6e1f0b2",
"createdAt": "2026-10-26T12:00:00.000Z",
"site": {
"domain": "myapp.com"
},
"scan": {
"id": "3f1c2b9e-1111-4222-8333-944455556666",
"grade": "C",
"score": 67,
"reportUrl": "https://appsafe.dev/report/…"
},
"summary": "2 changes on myapp.com",
"changes": [
{
"type": "header_removed",
"severity": "high",
"subject": "content-security-policy",
"message": "content-security-policy header removed"
},
{
"type": "finding_new",
"severity": "critical",
"subject": "baas-supabase-table-readable",
"title": "Supabase tables readable without logging in",
"message": "New issue: Supabase tables readable without logging in"
}
]
}Änderungstypen: finding_new, finding_resolved, header_added, header_removed, header_weakened, header_changed, tls_changed, tls_expiring (mit days), script_domain_new, sri_missing, subdomain_new, subdomain_dangling, dns_changed. Schweregrade: low, medium, high, critical. Alarme enthalten nur Verschlechterungen, daher erscheinen finding_resolved und header_added im Dashboard und im Bericht, lösen aber allein keinen Alarm aus.
Signatur prüfen
Jede Webhook-Anfrage hat einen X-AppSafe-Signature-Header. Berechne ein HMAC-SHA256 mit dem Secret deines Kanals über den Zeitstempel, einen Punkt und den unveränderten Request-Body und vergleiche es in konstanter Zeit mit v1. Lehne Anfragen ab, deren Zeitstempel älter als 5 Minuten ist.
X-AppSafe-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">
X-AppSafe-Event: monitoring.changes | monitoring.testimport { createHmac, timingSafeEqual } from "node:crypto";
// header: the X-AppSafe-Signature value, e.g. "t=1761480000,v1=5d41…"
// body: the raw request body (string), before JSON.parse
export function verifyAppSafeSignature(secret, header, body) {
const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
const timestamp = Number(parts.t);
if (!parts.v1 || Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const expected = createHmac("sha256", secret).update(`${timestamp}.${body}`).digest();
const given = Buffer.from(parts.v1, "hex");
return given.length === expected.length && timingSafeEqual(given, expected);
}AppSafe sendet jeden Alarm einmal und versucht es nicht erneut. Antworte innerhalb von 8 Sekunden mit einem 2xx-Status. Das Dashboard zeigt den letzten Zustellungsfehler des Kanals.
Was Alarme nie enthalten
Alarm-Payloads enthalten Änderungstypen, Schweregrade, Befundtitel, Header-Namen, Hostnamen von Skripten und Subdomains sowie einen Link zum Bericht. Sie enthalten nie Details zu Befunden, Secrets (auch keine geschwärzten) oder personenbezogene Daten.