- AddLog() neuer Parameter 'persist' (default true) - 4 Routine-Poll-Logs nur noch im In-Memory-Log: - '0 PushEvents empfangen' - 'X Events, 0 neue PushEvents' - 'X Events, X neue PushEvents → X scannen' - 'X Diffs gescannt, 0 neue Keys' - 'X Diffs gescannt, X neue Keys' wird bei Keys > 0 weiterhin persistiert
166 lines
5.9 KiB
Markdown
166 lines
5.9 KiB
Markdown
# Umsetzungsplan: Google Dorks Scanner
|
||
|
||
## Zusammenfassung
|
||
Suche nach geleakten API-Keys über Google Programmable Search Engine (Custom Search JSON API).
|
||
Google-Dork-Queries wie `"sk-ant-api03"` finden Keys auf beliebigen Webseiten, Foren, Blogs und Dokumentationen.
|
||
|
||
## Warum Google Dorks?
|
||
- Google indexiert Milliarden von Seiten – Pastebin, StackOverflow, Foren, Blogs, Docs
|
||
- Dork-Queries mit exakten Key-Prefixes sind extrem präzise (wenig False Positives)
|
||
- Ergänzt Serper: Serper liefert Snippets, Google CSE liefert **andere Ergebnisse** (unterschiedliche Indexierung/Ranking)
|
||
- Findet Keys auf Seiten die Serper möglicherweise nicht abdeckt
|
||
|
||
## ⚠️ Einschränkung: Closed for New Customers
|
||
- **Die Custom Search JSON API ist für Neukunden gesperrt** (seit ~2026)
|
||
- Bestehende Kunden haben bis **1. Januar 2027** Zugriff
|
||
- Google empfiehlt als Alternative: Vertex AI Search (bis 50 Domains) oder kostenpflichtige Full-Web-Search
|
||
- **Konsequenz:** Nur umsetzbar wenn der User bereits einen CSE-Account hat oder eine Alternative nutzt
|
||
- Der Plan wird trotzdem erstellt, da bestehende Accounts weiterhin funktionieren
|
||
|
||
## API-Analyse
|
||
|
||
### Custom Search JSON API
|
||
```
|
||
GET https://www.googleapis.com/customsearch/v1?key={API_KEY}&cx={SEARCH_ENGINE_ID}&q="sk-ant-api03"
|
||
```
|
||
|
||
- **100 Queries/Tag gratis** (danach $5 pro 1.000 Queries, max 10.000/Tag)
|
||
- Benötigt: Google Cloud API Key + Programmable Search Engine ID (cx)
|
||
- PSE muss auf "Search the entire web" konfiguriert sein
|
||
- Max 10 Ergebnisse pro Query (paginierbar mit `start` Parameter, max 100 Ergebnisse pro Query)
|
||
- Response: JSON mit `items[].link`, `items[].snippet`, `items[].title`
|
||
|
||
### Suchstrategie
|
||
Mit 100 Queries/Tag und max 10 Ergebnissen/Query → **max 1.000 URLs pro Tag**.
|
||
|
||
Optimale Verteilung der 100 Queries:
|
||
- Anthropic-Patterns: ~20 Queries (höchste Priorität)
|
||
- OpenAI-Patterns: ~20 Queries
|
||
- Andere Key-Typen: ~20 Queries
|
||
- Varianten/Ergänzungen: ~20 Queries
|
||
- Reserve: ~20 Queries
|
||
|
||
### Dork-Queries (Beispiele)
|
||
```
|
||
"sk-ant-oat01-"
|
||
"sk-ant-api03-"
|
||
"sk-proj-" "ANTHROPIC_API_KEY"
|
||
"ANTHROPIC_API_KEY" filetype:env
|
||
"sk-ant-" site:pastebin.com
|
||
"sk-ant-" site:gist.github.com
|
||
"sk-ant-" site:stackoverflow.com
|
||
"AKIA" "secret" filetype:env
|
||
"ghp_" site:pastebin.com
|
||
```
|
||
|
||
## Implementierungsplan
|
||
|
||
### Phase 1: Config – Server Settings
|
||
|
||
Zwei neue Settings in `ServerSettingsService.cs`:
|
||
```csharp
|
||
("GoogleCseApiKey", "text", "", "API", "Google CSE API Key", "API Key für Google Custom Search JSON API"),
|
||
("GoogleCseEngineId", "text", "", "API", "Google CSE Engine ID", "Search Engine ID (cx) der Programmable Search Engine"),
|
||
```
|
||
|
||
### Phase 2: Neue Scan-Methode `ScanGoogleCse`
|
||
|
||
```csharp
|
||
private async Task<List<(string Key, string Url)>> ScanGoogleCse(CancellationToken ct)
|
||
```
|
||
|
||
**Ablauf:**
|
||
1. Settings `GoogleCseApiKey` und `GoogleCseEngineId` laden
|
||
2. Für jeden Suchbegriff aus `KeyPatterns.ForCodeSearch`:
|
||
- Query bauen: `"sk-ant-oat01"` (exakte Phrase)
|
||
- `GET https://www.googleapis.com/customsearch/v1?key={key}&cx={cx}&q={query}&num=10`
|
||
- Response parsen: `items[].snippet` + `items[].link`
|
||
- Snippets mit `KeyPatterns.Compiled` Regex scannen
|
||
- Bei Treffer: Key + URL sammeln
|
||
- Optional: Seite herunterladen und vollständig scannen (bei Snippet-Treffern)
|
||
3. Query-Budget tracken (max 100/Tag)
|
||
4. Zwischen Requests: 1s Pause (kein offizielles Rate-Limit, aber Best Practice)
|
||
|
||
### Phase 3: Integration in RunScan
|
||
|
||
```csharp
|
||
// In RunScan(), nach Serper-Scan:
|
||
if (mode != "quick")
|
||
{
|
||
var cseApiKey = _settings.Get("GoogleCseApiKey");
|
||
var cseEngineId = _settings.Get("GoogleCseEngineId");
|
||
if (!string.IsNullOrWhiteSpace(cseApiKey) && !string.IsNullOrWhiteSpace(cseEngineId))
|
||
{
|
||
SetProgress("Google Custom Search", "Starte…");
|
||
var cseKeys = await ScanGoogleCse(ct);
|
||
allFoundKeys.AddRange(cseKeys.Select(k => (k.Key, k.Url, "google_cse")));
|
||
AddLog("scan", "Google CSE: " + cseKeys.Count + " Key(s) gefunden");
|
||
}
|
||
}
|
||
```
|
||
|
||
- **Mode `quick`:** Kein CSE-Scan (Query-Budget schonen)
|
||
- **Mode `web`:** CSE-Scan aktiv (Web-Quelle)
|
||
- **Mode `full`:** CSE-Scan aktiv
|
||
|
||
### Phase 4: Query-Budget-Management
|
||
|
||
Da nur 100 Queries/Tag gratis sind, braucht es ein Budget-Tracking:
|
||
|
||
```csharp
|
||
// Tägliches Query-Budget
|
||
private int _cseQueriesUsedToday;
|
||
private string _cseLastResetDate;
|
||
|
||
private bool CanUseCseQuery()
|
||
{
|
||
var today = DateTime.UtcNow.ToString("yyyy-MM-dd");
|
||
if (_cseLastResetDate != today)
|
||
{
|
||
_cseQueriesUsedToday = 0;
|
||
_cseLastResetDate = today;
|
||
}
|
||
return _cseQueriesUsedToday < 100;
|
||
}
|
||
```
|
||
|
||
### Phase 5: Snippet-Scanning vs. Page-Download
|
||
|
||
**Zwei Strategien:**
|
||
|
||
1. **Snippet-Only (empfohlen):** Google-Snippets enthalten oft genug vom Key um ihn zu erkennen. Spart Requests und ist schnell.
|
||
2. **Snippet + Page-Download:** Wenn Snippet einen Partial-Match hat (Key-Prefix aber nicht vollständig), die Seite herunterladen und vollständig scannen. Kostet zusätzliche HTTP-Requests, findet aber mehr Keys.
|
||
|
||
**Empfehlung:** Snippet-Only als Standard, Page-Download optional.
|
||
|
||
## Response-Format
|
||
|
||
```json
|
||
{
|
||
"items": [
|
||
{
|
||
"title": "Some Forum Post",
|
||
"link": "https://example.com/post/123",
|
||
"snippet": "...my API key is sk-ant-api03-abc123..."
|
||
}
|
||
],
|
||
"searchInformation": {
|
||
"totalResults": "42"
|
||
}
|
||
}
|
||
```
|
||
|
||
## Aufwandsschätzung
|
||
- **Implementierung:** ~150-200 Zeilen Code
|
||
- **Komplexität:** Niedrig (einfache REST API, Standard JSON)
|
||
- **Erwarteter Ertrag:** Mittel (ergänzt Serper, andere Ergebnisse möglich)
|
||
- **Kosten:** Gratis bis 100 Queries/Tag, danach $5/1.000
|
||
|
||
## Risiken
|
||
- ⚠️ **API ist für Neukunden gesperrt** – nur mit bestehendem Account nutzbar
|
||
- ⚠️ **Deadline: 1. Januar 2027** – danach muss auf Alternative migriert werden
|
||
- 100 Queries/Tag sind begrenzt → intelligente Query-Auswahl nötig
|
||
- Snippets können abgeschnittene Keys enthalten → Page-Download als Fallback
|
||
- Überschneidung mit Serper möglich → Deduplication über `_db.ScannedKeyExists()`
|
||
- Google kann Keys in Snippets maskieren (unwahrscheinlich, aber möglich)
|