Nyhet

Cloudflare Images får direktuppladdning i Workers: testa länken innan du släpper in användare

En webbläsare kan nu få en uppladdningslänk utan ditt Images API-token. Det gör flödet smidigare, men bevisar inte vem användaren är. Prova livslängd, engångsbeteende, ägarskap och privat leverans som ett sammanhängande kontrakt.

3 sep 2026

Ett nätformat huvud står framför svarta serverliknande skåp med gröna ljuslinjer och ett grönt hänglås.
Uppladdning och leverans är två skilda dörrar: båda behöver en kort livslängd och en kontrollerad mottagare.

Kort sagt

Skapa en uppladdningslänk först efter din egen inloggnings- och behörighetskontroll. Sätt requireSignedURLs: true och en uttrycklig kort livslängd, bind bild-id till användaren på serversidan och signera bara rätt variant efter en ny ägarkontroll. Godkänt prov kräver en tillåten uppladdning och fyra negativa fall: återanvänd länk, utgången länk, osignerad privat leverans och en annan användares bild.

Nyheten flyttar två känsliga steg in i bindingen

Den 2 september 2026 meddelade Cloudflare att Images binding för Workers har fått två nya hanteringsfunktioner. Cloudflares lanseringsnotis namnger createDirectUpload(), som utfärdar en Direct Creator Upload-länk, och signedUrl(), som skapar en signerad URL för en privat bild. Webbläsaren kan därmed skicka bildbytes direkt till Cloudflare, och senare hämta en privat variant direkt, utan att Workern förmedlar filen.

Det minskar mängden känsligt material i klienten. Enligt referensen för Images binding behöver klienten inget API-token för direktuppladdningen, och signeringen sker hos Cloudflare så att Workern inte hanterar kontots signeringsnyckel. Hosted image-operationer kräver dock en betald Images-plan med lagring. Kontrollera därför funktionen i ett separat testkonto eller en isolerad miljö, inte med riktiga användarbilder.

Tokenlös är inte behörig

Uppladdningsadressen är i praktiken en tillfällig rättighet. Den som får tag i den kan använda den utan ytterligare Images-autentisering. Din endpoint som utfärdar adressen måste därför själv kontrollera session, rätt att ladda upp, användarkvot och anropsfrekvens. Lägg inte en öppen /uploads-route framför bindingen och kalla avsaknaden av API-token för åtkomstkontroll.

1. Sätt de två livslängderna uttryckligen

Standarderna är för öppna för ett skarpt säkerhetsprov. requireSignedURLs är false om du inte sätter värdet. En direktuppladdningslänk gäller som standard i 1 800 sekunder; expiresIn accepterar 120–21 600 sekunder. För signedUrl() är expiresIn också valfritt, men där betyder ett utelämnat värde enligt dokumentationen att leveranslänken inte upphör. Uppladdningslänkens tid och bildlänkens tid är alltså två separata beslut.

Koppla bindingen som IMAGES i Wrangler-konfigurationen. Exemplet använder den kortaste dokumenterade uppladdningstiden, 120 sekunder, och låter Cloudflare skapa bildens id. Det senare är viktigt: dokumentationen för Direct Creator Upload säger att bilder med egna custom ID inte kan göras privata med signerade URL-token.

{
  "images": { "binding": "IMAGES" }
}
async function issueUpload(request, env) {
  const session = await requireSession(request, env);
  await assertMayUpload(session.userId, env);

  const result = await env.IMAGES.hosted.createDirectUpload({
    creator: session.userId,
    metadata: { ownerId: session.userId, purpose: "avatar-test" },
    requireSignedURLs: true,
    expiresIn: 120,
  });

  return Response.json({ id: result.id, uploadURL: result.uploadURL });
}

requireSession() och assertMayUpload() är avsiktligt applikationskod, inte Cloudflare-funktioner. De ska verifiera den identitet och den kvot som ditt system faktiskt använder. Returnera länken till den inloggade klienten men skriv den inte i analyslogg, felrapport eller skärmdump. För rutiner kring hemligheter och loggar, avgränsa detta prov mot Monkeybases guide till läckta hemligheter.

2. Prova engångslänken som en tillfällig credential

Begär en länk som användare A och ladda upp en liten syntetisk PNG som multipart-fältet file. Spara UTC-tid, testanvändare, bild-id, förväntad regel, statuskod och ett maskat svarsutdrag. Spara inte den fullständiga URL:en. Första försöket ska ge ett lyckat 2xx-svar.

curl -i -X POST "$UPLOAD_URL" \
  -F "file=@fixture.png;type=image/png"

Skicka därefter exakt samma fil till exakt samma URL en gång till. Cloudflare beskriver adressen som en engångslänk, men dokumentationen binder inte återanvändning till en viss statuskod. Godkänt resultat är därför att det andra försöket inte får 2xx; logga den faktiska koden och responsen. Skapa sedan en ny 120-sekunderslänk, lämna den oanvänd i mer än 120 sekunder och kontrollera även där ett icke-2xx-resultat.

Två prov, två nya länkar

Använd inte samma URL för återanvändnings- och utgångsprovet. Då vet du inte om den nekades för att den redan var förbrukad eller för att tiden hade gått ut.

3. Neka den publika vägen innan du signerar

Bygg en vanlig leveransadress för den uppladdade bildens testvariant utan signatur och anropa den. Enligt Cloudflares dokumentation om privata bilder ska en bild som kräver signerad URL inte kunna hämtas utan token. Undantaget är en variant som uttryckligen har gjorts offentlig. Använd därför en variant utan det undantaget och spara att den osignerade begäran inte gav 2xx.

Gör sedan en appkontrollerad endpoint för leverans. Den hämtar bildens metadata, jämför ownerId med den aktuella sessionen och ber bindingen signera just varianten private i 120 sekunder. Variantnamnet är en del av behörighetsbeslutet: låt inte klienten skicka ett godtyckligt variantnamn om olika varianter har olika offentlighet.

async function deliverImage(request, env, imageId) {
  const session = await requireSession(request, env);
  const image = env.IMAGES.hosted.image(imageId);
  const details = await image.details();

  if (!details) return new Response("Not found", { status: 404 });
  if (details.metadata?.ownerId !== session.userId) {
    return new Response("Forbidden", { status: 403 });
  }

  const url = await image.signedUrl({
    variant: "private",
    expiresIn: 120,
  });
  return Response.redirect(url, 302);
}

Hämta den signerade adressen som användare A och kontrollera 2xx före utgång. Prova samma adress igen efter mer än 120 sekunder och kräv icke-2xx. Logga inte frågeparametrarna i sin helhet. Den här server-side-vägen ersätter också äldre exempel där en signeringsnyckel läggs som Worker-hemlighet; om andra hemligheter ändå används ska de fortsatt hanteras enligt säkerhetsguidens gränser för känsliga data.

4. Gör användargränsen till ett eget negativt test

Logga in som användare B och be din leveransendpoint signera användare A:s bild-id. Rätt resultat i exemplet är HTTP 403 från din Worker före signedUrl(). Det är inte ett Cloudflare-löfte utan beviset för din egen ägarkontroll. Kör samma kontroll på endpointen som utfärdar uppladdningslänkar: en avstängd användare eller en användare utan kvarvarande kvot ska nekas innan en engångslänk skapas.

Tillåten uppladdning: användare A får en ny 120-sekunderslänk och första multipart-anropet ger 2xx.
Engångsbeteende: samma uppladdningslänk ger inte 2xx andra gången.
Utgång: en separat oanvänd uppladdningslänk ger inte 2xx efter mer än 120 sekunder.
Privat leverans: osignerad variant nekas, signerad variant fungerar före men inte efter sin 120-sekundersgräns.
Ägarskap: användare B får 403 innan Workern signerar användare A:s bild.

De fem raderna bevisar bara kontraktet du faktiskt körde. De visar inte att filen är ofarlig, att innehållet har modererats eller att all tenantisolering i applikationen är korrekt. Lägg sådana krav i separata kontroller. Om du automatiserar provet i CI, följ samma princip som i guiden till robusta API-integrationer: logga observerat beteende och skilj timeout, transportfel och avsiktlig nekning åt.

Källor

Uppgifterna kontrollerades mot Cloudflares primärkällor den 3 september 2026. API-yta, standardvärden och planvillkor kan ändras; kontrollera dokumentationen och spara faktiskt testsvar före driftsättning.

Fortsätt säkra
Sätt gränser för data, identitet och hemligheter