Zpět na domů

Bezpečný file upload v Go: 7 útoků

Článek popisuje ochranu file upload v Go před 7 útoky: podměna typu magic bytes, DoS přes MaxBytesReader+sloty, path traversal fixními cestami. Použita ECDSA-identifikace zařízení bez účtů pro browserové rozšíření.

7 útoků na file upload v Go a jejich ochrana
Advertisement 728x90

Ochrana nahrávání souborů v Go: ochrana proti 7 běžným útokům

V systémech bez tradiční autentizace je nahrávání souborů závislé na důvěryhodné identifikaci požadavků. Pro prohlížečové rozšíření PDF-to-Markdown byl implementován model na základě ECDSA P-256 prostřednictvím WebCrypto API. Při prvním spuštění se generuje neexportovatelná klíčová dvojice:

const keyPair = await crypto.subtle.generateKey(
  { name: 'ECDSA', namedCurve: 'P-256' },
  false,  // extractable = false
  ['sign', 'verify']
);

Veřejný klíč se zaregistruje na serveru, vrátí se device_id a device_token. Každý API požadavek obsahuje:

  • Authorization: Bearer <token>
  • X-Timestamp (±5 minut)
  • X-Nonce (proti opakování)
  • X-Body-SHA256
  • X-Signature (ECDSA nad METHOD+PATH+TIMESTAMP+NONCE+BODY_HASH)

Server ověřuje podpis pomocí veřejného klíče. Toto zajišťuje:

Google AdInline article slot
  • Omezení rychlosti na zařízení
  • Ochrana proti replay-útokům
  • Kontrola slotů (max. 3 aktivní úlohy)
  • Omezení registrací (5/IP/hodina)

Tento model zvyšuje náklady na útok: emulace vyžaduje kompletní implementaci ECDSA podpisů.

Útok 1: Podvržení typu souboru

Útočník maskuje spustitelný soubor jako PDF. Ochrana funguje na třech úrovních.

Frontend: Ověření MIME a přípony:

Google AdInline article slot
const ALLOWED_TYPES = ['application/pdf'];
const ALLOWED_EXTENSIONS = ['.pdf'];

function validateFile(file) {
  const isPdf = ALLOWED_TYPES.includes(file.type) ||
                ALLOWED_EXTENSIONS.some(ext =>
                  file.name.toLowerCase().endsWith(ext));
  if (!isPdf) return { valid: false, error: 'PDF pouze' };
}

Backend: Směrování podle Content-Type. Klíčové: Magic bytes:

pdfMagicBytes := "%PDF"
header4 := make([]byte, 4)
_, err := file.Read(header4)
if string(header4) != pdfMagicBytes {
    respondError(w, http.StatusBadRequest,
        models.ErrCodeValidationError,
        "Soubor není platný PDF")
}
file.Seek(0, 0)

Ověření prvních bajtů ignoruje hlavičky i přípony. Polyglot soubory (platné PDF + škodlivý kód) vyžadují další signatury.

Útok 2: Přeplnění disku

DoS útok pomocí velkých souborů. Omezení:

Google AdInline article slot
  • http.MaxBytesReader(w, r.Body, MaxFileSize + 1MB) — přeruší čtení přes limit.
  • Sloty na zařízení: max. 3 aktivní úlohy (queued, processing, ready, error).
  • Omezení rychlosti při registraci i požadavcích.

Identifikace zařízení činí změnu IP nebo tokenu neúčinnou.

Útok 3: Cesta traversal

Útočník používá ../../../etc/passwd. Řešení: Pevné jméno {UUID}/input.pdf. Uživatelský vstup v cestě je plně ignorován.

Sanitace frontendu (doplňková):

function sanitizeFileName(name) {
  return name
    .replace(/[/\\?%*:|"<>]/g, '-') 
    .replace(/^\.+/, '')
    .replace(/\.+$, '')
    .substring(0, 255)
    .trim();
}

Backend generuje cestu nezávisle na názvu souboru.

Útok 4: SSRF přes stahování z URL

Pro kanál "stažení z URL" jsou blokovány:

  • DNS resoluce před stažením
  • Přesměrování
  • Soukromé IP adresy (denylist: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)

Útok 5: Replay-útoky

X-Nonce + X-Timestamp + podpis. Nonce je uložen na zařízení, timestamp má okno ±5 minut.

Útok 6: Podvržení zařízení

extractable: false zabraňuje vývozu privátního klíče. Ukradení device_token je bezúčelné bez podpisu.

Útok 7: Zneužití na úrovni aplikace

Omezení rychlosti + sloty + podpis. Max. 3 sloty, 5 registrací/IP/hodina.

Co je důležité

  • Kryptografická identifikace na zařízení nahrazuje účty pro omezení.
  • Magic bytes (%PDF) jsou jediná spolehlivá kontrola typu souboru.
  • MaxBytesReader + sloty chrání proti DoS.
  • Fixní cesty vylučují traversal.
  • ECDSA P-256 + nonce/timestamp blokuje replay a podvržení.

— Editorial Team

Advertisement 728x90

Číst dál