it-swarm-eu.dev

Come limitare l'impatto e ridurre il rischio di iniezione SQL per il sito Web esistente?

Il nostro sito Web è basato su API al 100% (con un client SPA). Di recente, un hacker è riuscito a ottenere la password del nostro amministratore (con hash SHA-256) tramite SQL injection (e cracking pwd) in questo modo:

https://example.com/api/products?userId=3645&type=sqlinject here

È solo un esempio, ma è mortale per noi. Fortunatamente, era un hacker di Nizza e ci ha appena inviato un'e-mail sull'hacking. Fortunato per un sito Web sotto attacchi costanti durante i suoi 5 anni di esistenza.

Sì, sappiamo che dobbiamo controllare l'input dell'utente ovunque e formattare correttamente/escape/istruzioni preparate prima di inviare dati a MySQL. Lo sappiamo e lo stiamo risolvendo. Ma non abbiamo abbastanza sviluppatori/tester per renderlo sicuro al 100%.

Ora supponendo che abbiamo lo 0,1% di probabilità di essere iniettati SQL in qualche modo. Come possiamo rendere più difficile per gli hacker trovarlo e limitare il danno possibile?

Cosa facciamo fino a soluzioni rapide/misure aggiuntive:

  1. All'uscita "gate" condivisa da tutte le API, non inviamo più il PDOException e il messaggio non elaborati come prima. Ma dobbiamo ancora dire al cliente che si è verificata un'eccezione:

    {type: exception, code: err643, message: 'contact support for err643'}
    

    Sono consapevole che se un hacker vede un'eccezione, continuerà a provare ...

  2. L'utente PHP utilizza per connettersi a MySQL può solo CRUD alle tabelle. È abbastanza sicuro?

  3. Rinomina tutte le tabelle (usiamo open source in modo che l'hacker possa indovinare il nome delle tabelle).

Cos'altro dovremmo fare?

Aggiornamento: poiché ci sono molti commenti, vorrei dare alcune informazioni collaterali

  1. Prima di tutto, questa è l'app LEGACY, sviluppata da alcune persone simili a studenti, non di livello aziendale. Il team di sviluppo non si trova da nessuna parte, ora solo 1-2 ragazzi ibridi dev-test gestiscono centinaia di classi di accesso ai dati.
  2. La password è hash con SHA-256, sì fa schifo. E lo stiamo cambiando nel modo php raccomandato.
  3. SQL injection ha 17 anni. Perché è ancora in circolazione?
  4. Le istruzioni preparate sono sicure al 100% contro l'iniezione di SQL?
34
Phung D. An

Non dedicare molto tempo a soluzioni alternative o mezze correzioni. Ogni minuto che spendi cercando di implementare qualsiasi cosa suggerita qui è un minuto che potresti aver speso per implementare dichiarazioni preparate. Questa è l'unica vera soluzione.

Se hai una vulnerabilità di SQLi, l'attaccante probabilmente vincerà alla fine, qualunque cosa tu faccia per cercare di rallentarla. Quindi tieni presente che mentre potresti apportare miglioramenti, alla fine stai giocando una partita persa a meno che tu non risolva la causa principale del problema.

Per quanto riguarda ciò che hai provato finora: nascondere i messaggi di errore è un buon inizio. Ti consiglierei di applicare permessi ancora più severi (vedi sotto). È discutibile se cambiare i nomi delle tabelle aiuta , ma probabilmente non farà male.

Ok, allora che mi dici di quei permessi? Limitare ciò che l'utente del database può fare il più possibile, fino alla tabella o persino a livello di colonna. Puoi persino creare più utenti di database per bloccare ancora di più le cose. Ad esempio, utilizzare un utente del database solo con l'autorizzazione a scrivere quando si sta effettivamente scrivendo. Connettiti con un utente che ha il diritto di leggere la colonna della password solo quando devi effettivamente leggere la colonna della password. In questo modo, se si riscontra una vulnerabilità legata all'iniezione in un'altra query, non è possibile sfruttare la perdita delle password.

Un'altra opzione è quella di utilizzare un firewall per applicazioni Web (WAF), come mod_security per Apache. Puoi configurarlo per bloccare le richieste che sembrano sospette. Tuttavia, nessun WAF è perfetto. E ci vuole tempo ed energia per configurarlo. Probabilmente stai meglio usando quel tempo per implementare dichiarazioni preparate.

Ancora una volta, non lasciare che nulla di tutto ciò ti attiri in un falso senso di sicurezza. Non è possibile sostituire la causa principale del problema.

80
Anders

L'unico modo corretto è utilizzare dichiarazioni preparate.

  1. Se nascondi i messaggi di errore, sarà un po 'più difficile, ma non fermerà gli attaccanti.
  2. È possibile limitare i diritti, ma tutti i diritti concessi all'utente potrebbero essere acquisiti dall'aggressore. In alcuni casi è anche possibile eseguire comandi Shell da un'iniezione SQL.
  3. Rinominare le tabelle non ti aiuterà. Lo strumento sqlmap forzerà i nomi di tabella per il tuo carattere in base al carattere. Questo non richiede molto tempo.

Potresti anche limitare il numero di chiamate, rendere più difficile per gli aggressori o inviare avvisi su chiamate sospette e interrompere questo manuale, ma l'unico modo corretto per risolvere questo problema è utilizzare dichiarazioni preparate. Basta scorrere il codice sorgente e dare un'occhiata a istruzioni SQL con contenuti dinamici e sostituirli.

65
trietend

Lo sappiamo, ma non abbiamo abbastanza sviluppatori/tester per renderlo sicuro al 100%.

Questo è il vero problema. Fino a quando non assumerai più persone o riassegnerai le priorità, non sarai al sicuro. L'arresto del 99,9% degli aggressori significa che i tuoi dati sono stati compromessi. Le soluzioni di cerotto sono una cosa cattiva e non funzionano. Non perdere tempo a riformattare il tuo modello di accesso SQL mentre potresti risolvere problemi reali.

Per quanto riguarda la soluzione di codice, l'utilizzo di istruzioni preparate, come suggeriscono molte persone qui, è il modo più semplice per utilizzare SQL in sicurezza.

È molto più facile che provare a usare php per ripulire gli argomenti da soli e costa molto meno tempo. Basta eseguire il grep dell'intera base di codice per tutto ciò che riguarda SQL e risolverlo.

25
Gloweye

Elimina per sempre tutto il codice SQL dal tuo codice

La migliore soluzione a questo problema è eliminare tutto il codice SQL come stringhe letterali dal codice e non introdurlo mai più. Invece, usa ORM software come Hibernate o Entity Framework. Questo software è molto più bello da usare rispetto a SQL raw e parametrizza automaticamente il tuo SQL quando alla fine va al database. Se è possibile per te, avere questa politica.

Se non si ha il tempo di apprendere e implementare questi pacchetti o non è possibile utilizzarli per qualche altro motivo, la risposta di trietend è la cosa migliore successiva, usando istruzioni preparate . Ciò consentirà di essere al sicuro dall'iniezione SQL. Cioè, fino a quando non fai pressione sui tuoi sviluppatori per fornire soluzioni rapide, in quel momento potrebbero ancora una volta dimenticare di parametrizzare una singola variabile, lasciandoti indietro da dove hai iniziato.

Lo sappiamo, ma non abbiamo abbastanza sviluppatori/tester per renderlo sicuro al 100%.

Non è del tutto chiaro cosa intendi con questa affermazione, poiché le dichiarazioni preparate sono banali in ogni linguaggio web popolare (PHP, Python, Java, node.js, ecc.) E sono più o meno una misura efficace al 100% contro l'iniezione SQL .

Intendi subappaltare lo sviluppo e non puoi permetterti di QA il codice che scrivono per te sul contratto? Non puoi permetterti di non farlo: sei ancora la parte responsabile qui.

Vuoi dire che i tuoi sviluppatori sono troppo impegnati nell'implementazione delle funzionalità per impiegare alcune ore ad aggiornare la base di codice? Qualsiasi cosa diversa dalle dichiarazioni preparate richiederà più tempo e costerà di più (ad es. ORM, ostruzione, autorizzazioni dettagliate, ecc.).

Vuoi dire che i tuoi sviluppatori non sono abbastanza competenti per eseguire questo semplice compito? Questo è un grosso problema (o per essere più precisi, l'iniezione di SQL non dovrebbe essere la tua più grande preoccupazione a quel punto).

Vuoi dire che la tua base di codice è un tale pasticcio di logica spaghetti formattato come un fucile di nidificati includes che anche gli sviluppatori competenti impiegheranno un'eternità per eseguire quello che altrimenti sarebbe un semplice compito di poche ore? Allo stesso modo, problema più grande.

Qualunque sia, la soluzione è usare dichiarazioni preparate, circa ieri.

9
Jared Smith

Una volta implementato il consiglio iniziale di "dichiarazione preparata", consiglierei alcune letture sull'iniezione di SQL. Chiedere "come prevenire l'iniezione di SQL" è una domanda piuttosto ampia! La sicurezza è un argomento che tu (piuttosto, tutto il tuo team di sviluppo) devi conoscere molto per ridurre il rischio di compromesso. Una buca mina tutti gli altri tuoi sforzi.

Visita l'Open Web Application Security Project (OWASP) qui: https://www.owasp.org/index.php/SQL_Injection

In particolare il materiale aggiuntivo:

  • Foglio informativo sulla prevenzione dell'iniezione SQL
  • Foglio informativo sulla parametrizzazione delle query
  • Articolo di guida su come evitare le vulnerabilità legate all'iniezione di SQL

E anche

  • Come rivedere il codice per le vulnerabilità legate all'iniezione di SQL .
5
Nicolas

Una misura di stopgap sarebbe quella di esaminare un firewall per applicazioni web (WAF) - ci sono alcune aziende là fuori che forniscono questo come servizio e alcuni fornitori di cloud che hanno anche offerte. CloudFlare sembra offrirne uno, ho avuto un client che utilizza Incapsula e so che l'offerta AWS WAF ha alcune regole gestite per l'iniezione SQL.

Il modo in cui funziona è che tutto il traffico viene inviato a/attraverso il WAF (includendolo nei server o impostando il DNS in modo che punti al WAF come faresti per una CDN) e cerca cose che sembrano tentativi di iniezione SQL in i parametri. Non catturerà tutti gli attacchi e potrebbe bloccare il traffico legittimo, ma è una correzione bandaid disponibile.

4
CoderTao

Con "non ho abbastanza sviluppatori", intendo che alcune persone influenti nella tua organizzazione pensano che ci siano priorità più alte, quindi qualunque risorsa tu abbia è dedicata a quelle cose. Quindi, risolvere il problema di sicurezza sta perdendo altro in un'analisi costi-benefici.

Il tuo compito qui è quello di cambiare idea, tanto quanto implementare la correzione. Quantificare ciò che è in gioco: quale sarebbe il danno, sia in termini monetari che di reputazione, di un'altra violazione? Potrebbero esserci delle leggi nella tua giurisdizione che richiedono ti segnalano compromessi sui dati del tuo utente. Sarebbe imbarazzante? Potrebbero esserci notizie dei media sulle cattive pratiche della tua organizzazione?

Pensa all'investimento per fissare la sicurezza come un'assicurazione. In retrospettiva, dopo aver saputo che il tuo edificio non è andato in fumo per un periodo di dieci anni, potresti sostenere che i tuoi premi sono stati uno spreco. Ma tu e la tua organizzazione fate pagate per l'assicurazione, perché affrontate un futuro incerto. È la gestione del rischio.

Il rischio ha due fattori: probabilità e impatto. La probabilità che si verifichi un'altra violazione è alta: sai che è possibile ed è stata fatta almeno una volta. Se anche le potenziali conseguenze sono negative, è necessario aumentare la priorità di correzione delle vulnerabilità della sicurezza.

2
Concrete Gannet

Come tutti hanno già detto, correggi il codice sul sito.

Puoi fare qualsiasi patch tu voglia su un muro, ma fino a quando il muro non viene costruito correttamente qualsiasi patch sarà un problema di sanguinamento.

Qualsiasi altro suggerimento per ripulire il codice è ciò che Linus Torvalds chiamerebbe masterbation.

  • Correggi il tuo codice (dai punti di iniezione più ovvi all'ultimo I.E Ottieni parametri) e usa le istruzioni preparate. come posso prevenire l'iniezione sql in php

    • Puoi provare a [~ # ~] waf [~ # ~] (IE ModSecurity ) temporaneamente finché non sei in grado per sistemare le cose.

    • Prova forse una sorta di divieto IP su "persone che testano il sito" o bloccano l'esecuzione di query non sicure.

    • Se hai la possibilità di creare una schermata di accesso temporanea (sicura) di fronte fino a quando questo non viene risolto.

    • Prova un servizio di terze parti fino a quando non viene risolto qualcosa come cloudflare o qualsiasi altra cosa sia disponibile.

I PDO sono disponibili da PHP 5.1 rilasciato il 24 novembre 2005 ... Gli sviluppatori devono capire che sono conseguenze per le loro cattive abitudini di codifica e penso personalmente che ci dovrebbe essere responsabilità per la qualità di lavoro fornito.

In ogni caso i DOP sono una cosa facile da implementare. Se i tuoi sviluppatori non sono in grado di fornire una migliore qualità, suggerirei una purga ...

1
Qndel

Oltre a tutte le ottime risposte finora, se si desidera affrontare il problema specifico dell'estrazione delle credenziali dell'utente, è possibile riformattare il database per avere le password in una tabella separata con diritti di accesso rigorosi, simile a il modo in cui i sistemi Unix li inseriscono in/etc/shadow.

Per verificare le credenziali, è necessaria una procedura memorizzata che accetta la password immessa (o l'hash) come parametro e restituisce un valore booleano. In altre parole, si scarica il lavoro di verifica delle credenziali nel database e l'hash reale non lascia mai il database.

Ciò richiede un refactoring minimo e risolve il problema immediato alla radice, anziché una specifica iniezione SQL, lasciandoti vulnerabile a quello successivo.

0
Tom

La regola più importante è:

sa librerie, strumenti e API che rendono l'opzione sicura l'opzione più semplice.

Nacht dice "usa solo un ORM" che è un sottoinsieme di questa regola.

Le istruzioni preparate violano questa regola, poiché sono ingombranti da utilizzare, provocano un gonfiamento del codice, inoltre possono spesso essere più lente delle istruzioni non preparate a seconda del database. Sono una soluzione valida, non criticherò nessuno che li utilizza, ma non sono necessariamente la soluzione migliore e più conveniente.

E ... vogliamo che l'opzione sicura sia facile e conveniente, quindi il programmatore la usa per interesse personale e pigrizia. Vogliamo che il programmatore debba effettivamente fare di tutto per investire un po 'di sforzo al fine di utilizzare l'opzione non sicura! ...

Una soluzione molto migliore è un'API come Python dbapi. Ho scritto un php equivalente anni fa, che era come:

db_query( "SELECT * FROM mytable WHERE id=%s", $id )

Questo è più conveniente delle dichiarazioni preparate. Solo una riga da digitare. Inoltre restituisce il risultato in una forma che può usare foreach (), quindi è molto più facile da usare di fetch () e cose. Ancora più importante, il codice nascosto dietro questa API gestirà l'escaping correttamente. Ciò rende irrilevanti le iniezioni di SQL. Gestisce circa il 99% delle query se non si utilizza un ORM. Le query dinamiche (in genere la ricerca) richiedono tuttavia una gestione speciale, ma è comunque facile.

Se tieni a mente questa regola, allora ad un certo punto dovrai chiederti perché devi usare htmlspecialchars () e perché la lingua non ha una funzione che renderebbe l'impostazione sicura (cioè, nessun XSS vuln) più facile da usare? Perché oh perché? Ed è allora che lasci cadere PHP.

0
peufeu