Ciao a tutti, Pat Reeves qui, di nuovo su botsec.net. È il 3 aprile 2026, e ho passato troppo tempo ultimamente a esaminare un particolare tipo di problemi legati ai bot che cominciano davvero a infastidirmi. Parliamo molto di botnet sofisticati, credential stuffing e tecniche avanzate di evasione, e giustamente. Ma a volte, è l’errore apparentemente piccolo, quasi banale, che lascia i buchi più grandi.
Oggi voglio parlare di qualcosa che riguarda meno i bot stessi e più le porte che lasciamo spalancate per loro. In particolare, sto parlando della minaccia silenziosa dei reindirizzamenti e delle forward insicure lato server. Non si tratta solo di SEO poisoning o di esperienza utente; quando vengono eseguiti in modo errato, queste azioni apparentemente innocue diventano un vettore principale per takeover di account gestiti da bot, esfiltrazione di dati e persino mappatura interna della rete. E credetemi, i bot stanno diventando veramente bravi a sfruttarli.
“Ma Pat, è solo un reindirizzamento, giusto?”
Questa è di solito la prima reazione che ricevo. “Invia solo l’utente a un’altra pagina. Qual è il grande problema?” Il grande problema, amici miei, è quando quella “pagina diversa” è determinata dall’input dell’utente senza una valida verifica. O quando una forward si fida internamente di parametri originati esternamente. È un classico problema di fiducia, e i bot prosperano in ambienti dove la fiducia è mal riposta.
Pensateci. Avete una pagina di login. Dopo una autenticazione riuscita, spesso reindirizzate l’utente alla propria dashboard o a una pagina richiesta in precedenza. A volte, questo URL di destinazione viene passato come parametro di query: /login?redirect_to=/dashboard. Sembra tutto a posto, giusto? Ma cosa succede se un bot cambia questo in /login?redirect_to=https://malicious-phishing-site.com/steal-creds? O, ancor peggio, /login?redirect_to=//internal-admin-panel.yourdomain.com?
Di recente ho consultato un’azienda di e-commerce di medie dimensioni che stava vivendo un aumento di quello che pensavano fosse “session hijacking.” Gli utenti segnalavano di essere disconnessi e reindirizzati a pagine strane, o peggio, di trovare il loro carrello popolato con articoli casuali e indirizzi di spedizione cambiati. Dopo molte indagini, abbiamo trovato il colpevole: un parametro di reindirizzamento non convalidato nel loro flusso post-login.
I loro sviluppatori, in fretta, avevano implementato un semplice reindirizzamento PHP:
<?php
if (isset($_GET['redirect_to']) && !empty($_GET['redirect_to'])) {
header("Location: " . $_GET['redirect_to']);
exit();
} else {
header("Location: /dashboard");
exit();
}
?>
Vedi il problema? Nessuna validazione. Un bot potrebbe effettuare il login, poi creare un URL come https://shop.example.com/post-login.php?redirect_to=//attacker.com/phish.html?stolen_session_id=ABCD123. L’utente, pensando di essere ancora sul sito legittimo, verrebbe reindirizzato, il proprio ID sessione potenzialmente esposto, e poi presentato con una pagina di login falsa. Non si trattava solo di un’ipotesi; stava accadendo. I bot automatizzavano la scoperta e lo sfruttamento di questa vulnerabilità, trasformando le sessioni utente legittime in opportunità di phishing.
Reindirizzamenti aperti: il difetto ovvio ma spesso trascurato
L’esempio sopra è un classico “reindirizzamento aperto.” Esiste da sempre, eppure continua a riapparire. Ai bot piace perché conferiscono legittimità agli attacchi di phishing. Se l’URL iniziale è https://yourbank.com/login?redirect_to=https://evil.com, un utente meno esperto potrebbe vedere solo “yourbank.com” e fidarsi.
Quindi, come lo risolviamo? Semplice. Whitelist, non blacklist. Non fidarti mai implicitamente degli URL di reindirizzamento forniti dagli utenti. Controlla invece se l’URL fornito corrisponde a un modello atteso o è all’interno del tuo dominio. In caso contrario, imposta una pagina sicura come predefinita.
Esempio pratico 1: Sicurezza dei reindirizzamenti in Python (Flask)
Diciamo che stai usando Flask. Un modello comune per i reindirizzamenti potrebbe apparire così (prima la versione vulnerabile):
# VULNERABLE Flask redirect
from flask import Flask, request, redirect, url_for
app = Flask(__name__)
@app.route('/login')
def login():
if not request.args.get('next'):
return "Per favore, effettua il login per continuare." # Segnaposto per il modulo di login reale
return f"Pagina di login per {request.args.get('next')}"
@app.route('/auth_success')
def auth_success():
next_url = request.args.get('next')
if next_url:
return redirect(next_url) # PERICOLO: Reindirizzamento aperto!
return redirect(url_for('dashboard'))
@app.route('/dashboard')
def dashboard():
return "Benvenuto nel tuo dashboard!"
# Per testare: http://127.0.0.1:5000/auth_success?next=https://malicious.com
Ora, sistemiamolo. Dobbiamo convalidare che next_url sia effettivamente un percorso interno o un percorso nel nostro dominio.
# SECURE Flask redirect
from flask import Flask, request, redirect, url_for
from urllib.parse import urlparse, urljoin
app = Flask(__name__)
def is_safe_url(target):
ref_url = urlparse(request.host_url)
test_url = urlparse(urljoin(request.host_url, target))
return test_url.scheme in ('http', 'https') and \
ref_url.netloc == test_url.netloc
@app.route('/auth_success')
def auth_success():
next_url = request.args.get('next')
if next_url and is_safe_url(next_url):
return redirect(next_url)
return redirect(url_for('dashboard'))
# Per testare:
# http://127.0.0.1:5000/auth_success?next=/dashboard
# http://127.0.0.1:5000/auth_success?next=https://malicious.com (verrà reindirizzato alla dashboard)
La funzione is_safe_url è fondamentale qui. Controlla se lo schema dell’URL di destinazione è HTTP/HTTPS e, soprattutto, se la sua posizione di rete (dominio) corrisponde alla nostra. Questo impedisce il reindirizzamento verso siti esterni.
Forward lato server: il cugino più subdolo
I reindirizzamenti sono operazioni lato client; il browser riceve un 302 e va da qualche altra parte. Le forward lato server sono diverse. Il server elabora internamente la richiesta per una risorsa diversa senza informare il client. L’URL nella barra degli indirizzi del browser non cambia.
Qui le cose diventano davvero interessanti per i bot, specialmente se stai usando framework che gestiscono queste operazioni internamente in base ai parametri della richiesta. Immagina un firewall delle applicazioni web (WAF) o un gateway API che ispeziona attentamente le richieste in arrivo. Se un bot riesce a ingannare la tua applicazione a eseguire una forward interna a un endpoint sensibile basato su un parametro esterno non convalidato, quel WAF o gateway potrebbe non vedere mai nemmeno la richiesta interna malevola.
Ho visto questo accadere con un’istituzione finanziaria. Avevano un endpoint API interno, /admin/audit_logs, accessibile solo da specifici indirizzi IP interni. La loro app web esposta al pubblico aveva una funzionalità di “visualizza dettagli transazione”, che, per motivi di prestazioni, utilizzava un forward interno a un generico servlet di “visualizzazione dati”, passando l’ID della transazione. Il servlet recuperava quindi i dati specifici.
Un bot ha scoperto che se passava un ID transazione appositamente creato che sembrava ../../admin/audit_logs (un tentativo di path traversal), il meccanismo di forward interno, a causa di una scarsa sanitizzazione, avrebbe risolto questo in /admin/audit_logs. Il server, pensando che si trattasse di una richiesta interna, ha bypassato la restrizione IP e ha servito i log di audit. Il bot non aveva nemmeno bisogno di essere su una rete interna; aveva solo bisogno di manipolare un parametro che veniva poi utilizzato per un forward interno.
Esempio pratico 2: Prevenzione del Path Traversal nei Forward (Java/JSP)
Nei servlet Java, potresti usare RequestDispatcher.forward(). Un esempio vulnerabile potrebbe apparire così:
// VULNERABLE Java Servlet forward
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/dataViewer")
public class DataViewerServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String resource = request.getParameter("resource"); // e.g., "transactionDetails.jsp"
if (resource != null && !resource.isEmpty()) {
RequestDispatcher dispatcher = request.getRequestDispatcher(resource); // PERICOLO: Path Traversal
dispatcher.forward(request, response);
} else {
response.getWriter().println("Parametri della risorsa mancanti.");
}
}
}
// Per testare: /dataViewer?resource=../../WEB-INF/web.xml (potrebbe esporre la configurazione interna)
Per mettere in sicurezza questo, devi assicurarti che il parametro resource non consenta il path traversal e punti solo a risorse interne previste e sicure. Anche in questo caso, la whitelist è la tua alleata.
// SECURE Java Servlet forward
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/dataViewer")
public class DataViewerServlet extends HttpServlet {
private static final String[] ALLOWED_RESOURCES = {
"/WEB-INF/jsp/transactionDetails.jsp",
"/WEB-INF/jsp/userDetails.jsp",
"/WEB-INF/jsp/productInfo.jsp"
};
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String resource = request.getParameter("resource");
if (resource != null && !resource.isEmpty()) {
// Normalizza il percorso per prevenire la traversata
String normalizedResource = new java.io.File(resource).getCanonicalPath();
String contextPath = request.getContextPath();
if (contextPath == null) contextPath = ""; // Gestisci il contesto radice
// Assicurati che il percorso normalizzato inizi con il percorso di contesto o sia assoluto
if (normalizedResource.startsWith(contextPath)) {
normalizedResource = normalizedResource.substring(contextPath.length());
}
boolean isAllowed = false;
for (String allowed : ALLOWED_RESOURCES) {
if (allowed.equals(normalizedResource)) { // Uguaglianza rigorosa per la whitelist
isAllowed = true;
break;
}
}
if (isAllowed) {
RequestDispatcher dispatcher = request.getRequestDispatcher(normalizedResource);
dispatcher.forward(request, response);
} else {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Accesso alla risorsa richiesta vietato.");
}
} else {
response.getWriter().println("Parametro risorsa mancante.");
}
}
}
In questa versione sicura, abbiamo un elenco predefinito di ALLOWED_RESOURCES. Cerchiamo anche di normalizzare il percorso (anche se getCanonicalPath() potrebbe non essere completamente affidabile per i percorsi web senza controlli aggiuntivi a seconda del contenitore servlet). La parte cruciale è controllare rigorosamente se la risorsa richiesta corrisponde a un’entrata nella nostra whitelist. Qualsiasi deviazione comporta una risposta vietata.
Perché i Bot Amano Questi Difetti
- Frutti a Basso Costo: Questi non sono sempre complessi zero-day. Spesso sono semplici errori di validazione dell’input che sfuggono alle revisioni del codice.
- Legittimità & Fiducia: I reindirizzamenti aperti consentono ai bot di creare URL di phishing che sembrano provenire da un dominio fidato.
- Superamento dei Controlli di Sicurezza: I reindirizzamenti lato server, quando sfruttati, possono aggirare le restrizioni a livello di rete e WAF progettate per le richieste esterne. La richiesta interna potrebbe apparire perfettamente legittima per il sistema interno.
- Scoperta Automatica: I bot sono eccellenti nel sondare parametri per questo tipo di vulnerabilità. Proveranno vari payload di traversata dei percorsi, URL esterni e percorsi interni finché non trovano qualcosa.
- Esfiltrazione Dati & ATO: Che si tratti di fuga di ID di sessione tramite reindirizzamenti o accesso a dati interni tramite reindirizzamenti, l’obiettivo finale è spesso l’acquisizione dell’account o il furto di dati.
Azioni Concreti per la Sicurezza dei Bot
Va bene, quindi cosa puoi effettivamente fare a riguardo?
- Audit dei tuoi Reindirizzamenti & Inoltri: Esamina il tuo codice. Cerca
header("Location:,response.sendRedirect,return redirect,RequestDispatcher.forward, e qualsiasi costrutto simile nel tuo framework. - Implementa una Whitelist Rigorosa: Per qualsiasi destinazione di reindirizzamento o inoltro che utilizza input forniti dall’utente, assicurati che l’input sia rigorosamente in whitelist.
- Per i reindirizzamenti: Controlla che il dominio di destinazione corrisponda al tuo, o che il percorso sia un percorso relativo interno.
- Per gli inoltri: Assicurati che la risorsa di destinazione sia uno dei set predefiniti di risorse interne sicure. Non consentire mai caratteri di traversata del percorso (
../,..\) nei parametri di inoltro.
- Utilizza Funzioni Sicure Fornite dal Framework: La maggior parte dei moderni framework web ha funzioni integrate per reindirizzamenti e inoltri sicuri. Usale! Non crearne di tue a meno che tu non capisca assolutamente le implicazioni di sicurezza. Ad esempio,
url_for()di Flask eredirect()di Django, quando utilizzate con nomi interni, sono generalmente più sicure rispetto alla manipolazione di stringhe raw. - Content Security Policy (CSP): Sebbene non sia una soluzione diretta per problemi lato server, una CSP robusta può mitigare l’impatto dei reindirizzamenti aperti prevenendo il caricamento di script e risorse da domini esterni non fidati, anche se un utente viene reindirizzato.
- Scansioni di Sicurezza Regolari & Test di Penetrazione: Includi controlli per vulnerabilità di reindirizzamenti aperti e inoltri nelle tue scansioni regolari. I bot stanno costantemente cercando questi, e anche il tuo team di sicurezza dovrebbe farlo.
Non si tratta di cose glamour. Non è questione dell’ultimo botnet alimentato dall’IA. Si tratta di una corretta igiene della sicurezza web fondamentale. Ma nel mondo della difesa contro i bot, garantire questi punti di accesso di base porta spesso ai risultati migliori. Non lasciare che il reindirizzamento utile della tua applicazione o l’inoltro interno diventino il miglior amico di un bot. Rimani vigile, rimani sicuro!
– Pat Reeves, botsec.net
🕒 Published: