Sicurezza di siti e app IA

CORS troppo aperti nelle API IA: come restringere l'asterisco

9 min di lettura
Laptop su scrivania scura: DevTools Headers con Access-Control-Allow-Origin ristretto a https://app.example.com evidenziato in arancione
Windows macOS Linux
Immagine generata: Alex Lunalbi · Gemini · ai riparo

L'IA può suggerire Access-Control-Allow-Origin: * per far sparire un errore CORS. Ecco come leggerlo in DevTools e restringerlo su Express e FastAPI.

Se stai assemblando un progetto con l’aiuto dell’IA, prima o poi il browser ti bloccherà con un errore in console: Cross-Origin Request Blocked (o CORS policy).

Incolli l’errore in ChatGPT o Claude e la risposta è spesso immediata: middleware CORS, due righe, errore sparito. Nei boilerplate che ho visto, però, la “cura” tipica può essere aprire tutto con Access-Control-Allow-Origin: * — non perché sia la policy corretta, ma perché fa sparire il blocco in DevTools.

Non è un errore di sintassi: è una policy legittima, usata nel contesto sbagliato. Nell’audit di sicurezza gratuito e nelle 7 falle del codice IA (letture opzionali) restano altri buchi strutturali; qui chiudo solo questo.

Ti mostro come leggerlo in DevTools, quando * è accettabile e come restringerlo su Express e FastAPI senza rompere l’app.

ℹ️ Nota / Prerequisito operativo
Ti servono: frontend + backend che parlano (anche in locale), DevTools del browser e, per il test finale, un terminale con curl. Tieni a portata l’elenco dei domini reali del frontend (produzione + localhost di sviluppo).

Che cos’è il CORS (in sintesi)

CORS (Cross-Origin Resource Sharing) non è un firewall del server: è una regola che il browser applica alle risposte lette da JavaScript.

Di base il browser impedisce a uno script su https://sito-a.com di leggere la risposta di https://api-b.com. Senza questa restrizione, una pagina malevola in un’altra scheda potrebbe interrogare altre origini usando il contesto del tuo browser (cookie di sessione inclusi, quando le regole lo consentono).

Per allentare il blocco, il backend dichiara chi può leggere la risposta con l’header Access-Control-Allow-Origin. Se il valore è *, sta dicendo: qualsiasi origine web può leggere questi dati via JS nel browser.

⚠️ Attenzione — Cosa CORS non fa
CORS non ferma curl, Postman, bot o un server malevolo che chiama la tua API direttamente. Chiunque può comunque colpire l’endpoint senza browser. Serve autenticazione, autorizzazione e (dove serve) rate limiting. CORS regola soprattutto cosa può fare JavaScript in un browser di un utente.

Quando l’asterisco è un problema

Scenario d'uso dell'API Uso di * accettabile? Perché e cosa comporta
Asset pubblici statici Immagini, font, CSS pubblici Sì Dati pubblici senza autenticazione. Chiunque può includerli; non ci sono segreti utente nella risposta.
API pubbliche in sola lettura Cataloghi aperti, meteo, open data Dipende Utile se vuoi che altri siti le consumino dal browser. Controlla gli abusi con rate limiting e quote.
API con dati utente o autenticazione Dashboard, account, cookie/token No Qualsiasi sito può far leggere al browser dell'utente (via JS) risposte che il tuo backend ha autorizzato come pubbliche per tutte le origini. Con cookie/token la posta in gioco sale.

🚨 Avviso critico — Credenziali e asterisco
Lo standard CORS vieta di combinare Access-Control-Allow-Origin: * con Access-Control-Allow-Credentials: true. Se l’IA ti ha generato allow_origins=["*"] e allow_credentials=True (tipico in FastAPI), i browser moderni rifiutano comunque le richieste con credenziali — oppure, se togli i credentials e lasci solo *, stai aprendo le risposte a ogni origine. Per API con sessione/cookie: whitelist di origini esatte + credentials: true, mai *.

CORS non sostituisce SameSite sui cookie né la protezione CSRF lato server: sono controlli diversi. Qui chiudo solo la policy Origin troppo larga.

Come leggere gli header in DevTools

Windows — Chrome o Edge (percorso principale)

  1. Apri l’app nel browser e fai login se serve.
  2. Premi F12 (o clic destro → Ispeziona).
  3. Scheda Network (Rete). Se è vuota, ricarica la pagina (Ctrl+R).
  4. Filtra per Fetch/XHR se la lista è rumorosa.
  5. Esegui l’azione che chiama l’API (click, submit, reload).
  6. Clicca la richiesta verso il backend.
  7. Pannello Headers → sezione Response Headers.
  8. Cerca access-control-allow-origin. Se vedi *, il backend sta autorizzando qualsiasi origine.

macOS — Chrome / Edge / Safari

  • Chrome/Edge: ⌘⌥I o F12 → Network → stessa lettura degli header.
  • Safari: attiva Sviluppo (Impostazioni → Avanzate), poi Ispeziona → Rete → seleziona la richiesta → header di risposta.

Linux — Chrome / Firefox

F12 → Network / Rete → stessa procedura. Su Firefox la scheda si chiama spesso Rete; gli header di risposta sono sotto la richiesta selezionata.

Dettaglio generico di header HTTP di risposta con Access-Control-Allow-Origin impostato a asterisco
In Network → Headers, la riga Access-Control-Allow-Origin ti dice subito se il backend risponde con un dominio preciso o con l’asterisco (una scorciatoia che l’IA può proporre).

💡 Consiglio pratico — Richiesta OPTIONS
Spesso compare una richiesta gemella con metodo OPTIONS (preflight): il browser chiede permesso prima di POST/PUT “non semplici”. Controlla anche lì Access-Control-Allow-Origin e Access-Control-Allow-Methods.

Come restringere il CORS in Express (Node.js)

Pattern pigro tipico:

const express = require('express');
const cors = require('cors');
const app = express();

// Genera Access-Control-Allow-Origin: *
app.use(cors());

Fix: passa un’origine (o una funzione di whitelist). Un’origine = protocollo + host + porta, senza path (https://www.tuosito.com, non https://www.tuosito.com/dashboard).

const express = require('express');
const cors = require('cors');
const app = express();

const whitelist = [
  'https://www.tuosito.com',
  'https://tuosito.com',
  'http://localhost:3000', // solo in sviluppo
];

const corsOptions = {
  origin: function (origin, callback) {
    // Richieste senza Origin (curl, server-to-server): spesso le lasci passare.
    // Dal browser, Origin è sempre presente nelle chiamate cross-origin.
    if (!origin || whitelist.includes(origin)) {
      callback(null, true);
    } else {
      callback(new Error('Non consentito dalla policy CORS'));
    }
  },
  // Se il frontend usa fetch(..., { credentials: 'include' }) con cookie:
  // credentials: true,
};

app.use(cors(corsOptions));

ℹ️ Nota / Prerequisito operativo
Con credentials: 'include' nel frontend devi credentials: true nel middleware e un’origine concreta (mai *). Dopo il deploy, togli dalla whitelist i localhost che non ti servono più in produzione (o usa variabili d’ambiente diverse per dev/prod).

Se usi npm per aggiungere il pacchetto e non ce l’hai:

Windows

npm install cors
npm list cors

macOS / Linux — stessi comandi npm install cors e npm list cors dal Terminale nella root del progetto.

Come restringere il CORS in FastAPI (Python)

Pattern pigro frequente (e spesso incoerente con lo standard):

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # problema
    allow_credentials=True,  # incompatibile con *
    allow_methods=["*"],
    allow_headers=["*"],
)

Versione ristretta:

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

origins = [
    "https://www.tuosito.com",
    "https://tuosito.com",
    "http://localhost:8000",  # solo test locali
]

app.add_middleware(
    CORSMiddleware,
    allow_origins=origins,
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
    allow_headers=["Content-Type", "Authorization"],
)

Riavvia l’app (uvicorn/gunicorn o il comando che usi) dopo la modifica. In produzione togli localhost dalla lista o caricala da env (CORS_ORIGINS=https://tuosito.com,https://www.tuosito.com).

Test finale prima e dopo

Dal terminale simula un’origine estranea con un preflight OPTIONS.

Windows (Prompt / PowerShell / Windows Terminal)

curl -i -X OPTIONS ^
  -H "Origin: https://sito-estraneo.example" ^
  -H "Access-Control-Request-Method: POST" ^
  https://api.tuosito.com/endpoint

In PowerShell moderno puoi usare la stessa riga su una sola linea:

curl -i -X OPTIONS -H "Origin: https://sito-estraneo.example" -H "Access-Control-Request-Method: POST" https://api.tuosito.com/endpoint

macOS / Linux

curl -i -X OPTIONS \
  -H "Origin: https://sito-estraneo.example" \
  -H "Access-Control-Request-Method: POST" \
  https://api.tuosito.com/endpoint

Cosa cercare nella risposta

  • Non deve comparire Access-Control-Allow-Origin: https://sito-estraneo.example.
  • Non deve comparire Access-Control-Allow-Origin: * (se hai stretto la policy).
  • Poi ritesta dall’app reale in DevTools: la tua origine in whitelist deve ricevere Access-Control-Allow-Origin: https://www.tuosito.com (o il dominio esatto che hai autorizzato), e l’app deve continuare a funzionare.

Se l’app si rompe dopo il fix, di solito manca un dominio in whitelist (www vs non-www, http vs https, porta di Vite/Next in locale). Aggiungi solo quell’origine, non tornare a *.

Domande Frequenti (FAQ)

Cos’è CORS e perché l’IA può suggerire Access-Control-Allow-Origin: *?

CORS (Cross-Origin Resource Sharing) decide se JavaScript di un’origine può leggere le risposte di un’API su un’altra origine. L’asterisco sblocca quasi ogni sito in un colpo solo: l’IA può proporlo perché fa sparire l’errore in DevTools al primo tentativo — non perché sia la policy corretta in produzione.

Quando Access-Control-Allow-Origin: * è davvero pericoloso?

È un problema quando l’API espone dati sensibili o azioni autenticate e un sito malevolo può far eseguire al browser dell’utente loggato richieste cross-origin leggibili. Per API pubbliche solo-lettura senza cookie, l’impatto può essere minore — ma in un login o in un backend “personale” messo online, meglio una whitelist esplicita.

Come verifico gli header CORS nel browser?

Apri DevTools → scheda Network, ricarica la pagina o ripeti la chiamata API, seleziona la richiesta e guarda Response Headers (e la preflight OPTIONS se c’è). Controlla Access-Control-Allow-Origin, Access-Control-Allow-Credentials e i metodi/header consentiti.

Come restringo il CORS in Express o FastAPI senza rompere il frontend?

Elenca solo le origini reali del tuo frontend (schema + dominio + porta, www vs non-www). Su Express usa un middleware CORS con origin array/callback; su FastAPI configura CORSMiddleware con la stessa whitelist. Dopo il fix, ritesta: l’origine autorizzata deve funzionare, un’origine estranea no.

No. Restringere l’asterisco limita cosa può leggere JavaScript cross-origin; non autentica i client, non nasconde l’API a chi la chiama fuori dal browser e non sostituisce flag come HttpOnly / SameSite sui cookie di sessione.

Cosa resta fuori da CORS

Restringere l’asterisco riduce ciò che JavaScript cross-origin può leggere nel browser. Non autentica i client, non nasconde l’API a chi la chiama fuori dal browser e non sostituisce cookie HttpOnly / SameSite (vedi la guida opzionale sui cookie di sessione sicuri).

Cinque minuti di whitelist esplicita, in produzione, chiudono uno dei “fix veloci” più comuni del vibe coding — senza togliere all’app la possibilità di parlare col proprio frontend.

Alex Lunalbi

Alex Lunalbi

Security & privacy

Dona su PayPal

Scrivo di sicurezza digitale pratica e codice IA. Su ai riparo ogni procedura è verificata su macchine reali.

Tag
  • sicurezza,
  • CORS,
  • API,
  • vibe coding