mirror of
https://github.com/alam00000/bentopdf.git
synced 2026-11-05 20:02:47 +01:00
181 lines
7.8 KiB
Markdown
181 lines
7.8 KiB
Markdown
# CORS-Proxy zum Abrufen von Zertifikaten
|
|
|
|
Das Werkzeug für digitale Signaturen nutzt einen CORS-Proxy, um Aussteller-Zertifikate von externen Zertifizierungsstellen (CAs) abzurufen. Das ist nötig, weil viele CA-Server keine CORS-Header in ihren Antworten mitsenden, wodurch ein direkter Abruf aus dem Browser verhindert wird.
|
|
|
|
Außerdem liefern viele CA-Server Zertifikate über einfaches HTTP aus. Wird Ihre BentoPDF-Instanz über HTTPS gehostet, blockieren Browser diese HTTP-Anfragen (Mixed-Content-Richtlinie). Der CORS-Proxy löst beide Probleme, indem er Anfragen über einen HTTPS-Endpunkt mit den passenden Headern leitet.
|
|
|
|
## So funktioniert es
|
|
|
|
Beim Signieren einer PDF mit einem Zertifikat:
|
|
|
|
1. Die Bibliothek `zgapdfsigner` versucht, eine vollständige Zertifikatskette aufzubauen
|
|
2. Sie ruft Aussteller-Zertifikate von URLs ab, die in der AIA-Erweiterung (Authority Information Access) Ihres Zertifikats eingebettet sind
|
|
3. Diese Anfragen laufen über einen CORS-Proxy, der die nötigen `Access-Control-Allow-Origin`-Header ergänzt
|
|
4. Der Proxy liefert die Zertifikatsdaten an den Browser zurück
|
|
|
|
## Den CORS-Proxy selbst hosten
|
|
|
|
Wenn Sie BentoPDF selbst hosten, müssen Sie einen eigenen CORS-Proxy bereitstellen, damit digitale Signaturen mit Zertifikaten funktionieren, die einen Abruf der Kette erfordern.
|
|
|
|
### Option 1: Cloudflare Workers (empfohlen)
|
|
|
|
1. **Wrangler CLI installieren**:
|
|
|
|
```bash
|
|
npm install -g wrangler
|
|
```
|
|
|
|
2. **Bei Cloudflare anmelden**:
|
|
|
|
```bash
|
|
wrangler login
|
|
```
|
|
|
|
3. **BentoPDF klonen und erlaubte Origins anpassen**:
|
|
|
|
```bash
|
|
git clone https://github.com/alam00000/bentopdf.git
|
|
cd bentopdf/cloudflare
|
|
```
|
|
|
|
Öffnen Sie `cors-proxy-worker.js` und änderen Sie das Array `ALLOWED_ORIGINS` auf Ihre Domain:
|
|
|
|
```js
|
|
const ALLOWED_ORIGINS = [
|
|
'https://your-domain.com',
|
|
'https://www.your-domain.com',
|
|
];
|
|
```
|
|
|
|
::: warning Wichtig
|
|
Ohne diese Änderung lehnt der Proxy alle Anfragen von Ihrer Website mit dem Fehler **403 Forbidden** ab. Standardmäßig sind nur Anfragen von `bentopdf.com` erlaubt.
|
|
:::
|
|
|
|
4. **Den Proxy bereitstellen**:
|
|
|
|
```bash
|
|
wrangler deploy
|
|
```
|
|
|
|
Notieren Sie sich die URL Ihres Workers (z. B. `https://bentopdf-cors-proxy.your-subdomain.workers.dev`).
|
|
|
|
5. **BentoPDF mit der Proxy-URL neu bauen**:
|
|
|
|
Bei Verwendung von Docker:
|
|
|
|
```bash
|
|
export VITE_CORS_PROXY_URL="https://your-worker.workers.dev"
|
|
DOCKER_BUILDKIT=1 docker build \
|
|
--secret id=VITE_CORS_PROXY_URL,env=VITE_CORS_PROXY_URL \
|
|
-t your-bentopdf .
|
|
```
|
|
|
|
Beim Bauen aus dem Quellcode:
|
|
|
|
```bash
|
|
VITE_CORS_PROXY_URL=https://your-worker.workers.dev npm run build
|
|
```
|
|
|
|
### Option 2: Eigener Backend-Proxy
|
|
|
|
Sie können auch einen eigenen Proxy-Endpunkt erstellen. Die Anforderungen sind:
|
|
|
|
1. GET-Anfragen mit einem Query-Parameter `url` annehmen
|
|
2. Die URL von Ihrem Server aus abrufen (serverseitig gibt es keine CORS-Beschränkungen)
|
|
3. Die Antwort mit diesen Headern zurückgeben:
|
|
- `Access-Control-Allow-Origin: https://your-domain.com`
|
|
- `Access-Control-Allow-Methods: GET, OPTIONS`
|
|
- `X-Content-Type-Options: nosniff`
|
|
|
|
Beispielimplementierung mit Express.js:
|
|
|
|
```javascript
|
|
app.get('/api/cert-proxy', async (req, res) => {
|
|
const targetUrl = req.query.url;
|
|
|
|
// Validate it's a certificate URL
|
|
if (!isValidCertUrl(targetUrl)) {
|
|
return res.status(400).json({ error: 'Invalid URL' });
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(targetUrl);
|
|
const data = await response.arrayBuffer();
|
|
|
|
res.set('Access-Control-Allow-Origin', 'https://your-domain.com');
|
|
res.set('Content-Type', 'application/octet-stream');
|
|
res.set('X-Content-Type-Options', 'nosniff');
|
|
res.send(Buffer.from(data));
|
|
} catch (error) {
|
|
res.status(500).json({ error: 'Proxy error' });
|
|
}
|
|
});
|
|
```
|
|
|
|
## Sicherheitshinweise
|
|
|
|
Der mitgelieferte Cloudflare Worker hat mehrere Sicherheitsmaßnahmen:
|
|
|
|
| Funktion | Beschreibung |
|
|
| ---------------------------- | ----------------------------------------------------------------------------------------------- |
|
|
| **Origin-Prüfung** | Erlaubt nur Anfragen von Domains aus `ALLOWED_ORIGINS` |
|
|
| **URL-Beschränkungen** | Erlaubt nur Zertifikat-URLs (`.crt`, `.cer`, `.pem`, `/certs/`, `/ocsp`, `/crl`) |
|
|
| **Blockierung privater IPs** | Blockiert private IPv4-/IPv6-Bereiche, Link-Local, Loopback, dezimale IPs und Cloud-Metadaten |
|
|
| **Content-Type-Sicherheit** | Liefert nur sicheren Sie Zertifikat-MIME-Typen, blockiert Content-Type-Injection vom Upstream |
|
|
| **Dateigrößenlimit** | Streamt die Antwort mit 10MB-Limit und bricht den Download bei Überschreitung ab |
|
|
| **Ratenbegrenzung** | 60 Anfragen pro Minute pro IP oder IPv6 /64 (erfordert KV, bei KV-Fehlern wird nicht blockiert) |
|
|
| **HMAC-Signaturen** | Optionale clientseitige Signierung (schreckt gelegentlichen Missbrauch ab) |
|
|
|
|
### DNS-Rebinding (Selbst-Hosting außerhalb von Cloudflare)
|
|
|
|
Der Worker lehnt jede URL ab, die auf eine private oder interne IP aufgelöst wird. Eine feste Allowlist von Hosts ist nicht möglich, da Zertifikatsketten-URLs auf die jeweilige CA verweisen, die das Zertifikat ausgestellt hat (FNMT, Unternehmens-CAs usw.), die Ziele also nicht im Voraus bekannt sind. Dadurch bleibt ein kleines Rebinding-Fenster: Wer das DNS für seine eigene Domain betreibt, könnte der Sicherheitsprüfung eine öffentliche IP liefern und der eigentlichen Anfrage einen Moment später eine private.
|
|
|
|
Auf Cloudflare ist das nicht ausnutzbar: Workers können weder private IPs noch den Metadaten-Endpunkt `169.254.169.254` erreichen, ein Rebind läuft also ins Leere. Geben Sie dem Worker nur keinen Zugang: Hängen Sie keinen Tunnel, Service oder kein Private-Network-Binding an (er braucht nur `RATE_LIMIT_KV`).
|
|
|
|
Betreiben Sie ihn außerhalb von Cloudflare (workerd, Node und Ähnliches) in einer VPC, _kann_ die Runtime interne IPs erreichen. Setzen Sie eine Egress-Firewall davor und blockieren Sie die privaten Bereiche: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `127.0.0.0/8`, `169.254.0.0/16` sowie die IPv6-Entsprechungen. Anwendungscode kann das außerhalb von Cloudflare nicht durchsetzen.
|
|
|
|
## Den Proxy deaktivieren
|
|
|
|
Wenn Sie keinen CORS-Proxy nutzen möchten, setzen Sie die Umgebungsvariable auf einen leeren String:
|
|
|
|
```
|
|
VITE_CORS_PROXY_URL=
|
|
```
|
|
|
|
**Hinweis**: Ohne den Proxy schlägt das Signieren mit Zertifikaten, die einen externen Abruf der Kette erfordern (wie FNMT oder einige Unternehmens-CAs), mit dem Fehler "Failed to fetch" fehl.
|
|
|
|
## Fehlerbehebung
|
|
|
|
### "Signing error: TypeError: Failed to fetch"
|
|
|
|
Das bedeutet meist eines von beidem:
|
|
|
|
1. **Kein CORS-Proxy konfiguriert**: Setzen Sie `VITE_CORS_PROXY_URL` und bauen Sie neu
|
|
2. **Mixed Content blockiert**: Ihre Website nutzt HTTPS, aber die Aussteller-URL des Zertifikats ist HTTP. Der CORS-Proxy löst das.
|
|
3. **CORS-Proxy lehnt Ihren Origin ab**: Prüfen Sie, ob Ihre Domain im Array `ALLOWED_ORIGINS` in `cors-proxy-worker.js` steht
|
|
|
|
### "403 Forbidden" vom Proxy
|
|
|
|
Ihre Domain steht nicht in der Liste `ALLOWED_ORIGINS`. Bearbeiten Sie `cors-proxy-worker.js`:
|
|
|
|
```js
|
|
const ALLOWED_ORIGINS = ['https://your-domain.com'];
|
|
```
|
|
|
|
Stellen Sie danach erneut bereit: `npx wrangler deploy`
|
|
|
|
### Den Proxy testen
|
|
|
|
```bash
|
|
curl -H "Origin: https://your-domain.com" \
|
|
"https://your-proxy.workers.dev?url=http://www.cert.fnmt.es/certs/ACUSU.crt"
|
|
```
|
|
|
|
### Zertifikate, die ohne Proxy funktionieren
|
|
|
|
Manche Zertifikate enthalten die vollständige Kette in der P12/PFX-Datei und benötigen keinen externen Abruf:
|
|
|
|
- Selbstsignierte Zertifikate
|
|
- Einige kommerzielle CAs, die Zwischenzertifikate mitliefern
|
|
- Zertifikate, die Sie manuell mit der vollständigen Kette zusammengestellt haben
|