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

34

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

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

È solo un esempio, ma per noi è mortale. Fortunatamente, è stato un bravo hacker e ci ha appena mandato un'email riguardo l'hack. Fortunato per un sito web sotto attacchi di costanti per tutti i suoi 5 anni di esistenza.

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

Ora supponiamo di avere una probabilità dello 0,1% di essere iniettati SQL in qualche modo. Come rendere più difficile per l'hacker trovarlo e limitare il danno il più possibile?

Cosa facciamo finora come soluzioni rapide / misure aggiuntive:

  1. All'uscita "gate" condivisa da tutte le API, non inviamo più il PDOException e il messaggio 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 l'hacker vedrà un'eccezione, continuerà a provare ...

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

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

Che altro dovremmo fare?

Update : since there are many comments, I would like to give some side info

  1. First of all, this is LEGACY app, developed by some student-like folks, not enterprise grade. The dev team is nowhere to be found, now only 1-2 hybrid dev-test guy handling hundreds of Data Access class.
  2. The password is hash with SHA-256, yes it sucks. And we are changing it to recommended php way.
  3. SQL injection is 17 years old. Why is it still around?
  4. Are prepared statements 100% safe against SQL injection?
    
posta Phung D. An 20.06.2018 - 21:41
fonte

11 risposte

80

Non passare molto tempo su 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à SQLi, l'attaccante probabilmente vincerà alla fine, indipendentemente da quello che fai per cercare di rallentarla. Quindi, tieni presente che mentre puoi apportare miglioramenti, alla fine stai giocando a perdere, a meno che non risolvi la causa principale del problema.

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

Ok, allora che mi dici di quelle autorizzazioni? Limita ciò che l'utente del database può fare il più possibile, fino al tavolo o addirittura a livello di colonna. Potresti persino creare più utenti di database per bloccare ancora di più le cose. Ad esempio, usa solo un utente del database con il permesso di scrivere quando stai scrivendo. Collegati solo con un utente che ha il diritto di leggere la colonna della password quando è effettivamente necessario leggere la colonna della password. In questo modo, se hai una vulnerabilità di iniezione in qualche altra query, non puoi sfruttare la perdita di password.

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

Ancora una volta, non lasciare che questo ti attiri in un falso senso di sicurezza. Non c'è sostituzione alla correzione della causa principale del problema.

    
risposta data 20.06.2018 - 22:08
fonte
65

L'unico modo corretto è usare le istruzioni preparate.

  1. Se si mascherano i messaggi di errore, è un po 'più difficile, ma non si fermano gli attaccanti.
  2. È possibile limitare i diritti, ma l'autore dell'attacco può ottenere tutti i diritti concessi all'utente. In alcuni casi è anche possibile eseguire comandi di shell da un'Iniezione SQL.
  3. Rinominare le tabelle non ti aiuterà. Lo strumento sqlmap impone la forza bruta ai nomi tabella per te char per char. Questo non ha bisogno di molto tempo.

Potresti limitare anche il numero di chiamate, rendere più difficile per gli aggressori o effettuare avvisi su chiamate sospette e interrompere questo manuale, ma l'unico modo corretto di risolvere questo problema è usare istruzioni preparate. Basta accedere al codice sorgente e dare un'occhiata alle istruzioni SQL con contenuto dinamico e sostituirle.

    
risposta data 20.06.2018 - 22:05
fonte
25

We know, but we do not have enough developers/testers to make it 100% safe.

Questo è il vero problema . Fino a quando non assumi più persone o riassegni le priorità, non sei al sicuro. Arrestare il 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 rielaborare il tuo modello di accesso SQL mentre potresti risolvere i problemi reali.

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

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

    
risposta data 21.06.2018 - 12:23
fonte
9

Elimina tutto il codice SQL dal tuo codice per sempre

La migliore soluzione a questo problema è eliminare tutto il codice SQL come stringhe letterali dal codice e non introdurlo mai più. Invece, utilizza 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 arriva al database. Se è possibile per te, hai questa politica.

Se non hai il tempo di imparare e implementare questi pacchetti, o non puoi usarli per qualche altro motivo, la risposta di trietend è la cosa migliore, usando istruzioni preparate . Ciò ti consentirà di essere al sicuro dall'iniezione SQL. Cioè, fino a quando non eserciti alcuna pressione sugli sviluppatori per fornire soluzioni rapide, in quel momento potrebbero ancora una volta dimenticare di parametrizzare una singola variabile, lasciandoti indietro dove hai iniziato.

    
risposta data 21.06.2018 - 07:37
fonte
9

We know, but we do not have enough developers/testers to make it 100% safe.

Non è del tutto chiaro cosa intendi con questa affermazione, dato che 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.

Vuoi dire che subappalti lo sviluppo e non puoi permetterti di controllare il codice che scrivono per te su contratto? Non puoi permetterti di non farlo: sei ancora la parte responsabile qui.

Intendi dire che i tuoi sviluppatori sono troppo impegnati nell'implementazione delle funzionalità per impiegare alcune ore ad aggiornare il codebase? Qualsiasi cosa diversa dalle dichiarazioni preparate richiederà più tempo e costa di più (ad es. ORM, obsfucation, permessi a grana fine, ecc.)

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

Intendi dire che il tuo codebase è un casino di spaghetti-formattato a shotgun di nidificati include s che anche gli sviluppatori competenti impiegheranno per sempre a eseguire quello che altrimenti sarebbe un compito semplice di poche ore? Allo stesso modo, un problema più grande.

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

    
risposta data 21.06.2018 - 16:18
fonte
5

Una volta implementato il consiglio iniziale di "istruzioni preparate", consiglierei alcune letture sull'iniezione SQL. Chiedere "come prevenire l'iniezione SQL" è una domanda piuttosto ampia! La sicurezza è un argomento che tu (piuttosto, l'intero team di sviluppo) deve avere molta familiarità per ridurre il rischio di compromissione. Un buco mina tutto il tuo sforzo.

Visita il progetto Open Web Application Security (OWASP) qui: link

In particolare il materiale aggiuntivo:

  • Scheda cheat di prevenzione dell'iniezione SQL
  • Scheda Cheat per la parametrizzazione delle query
  • Guida all'articolo su come evitare le vulnerabilità di SQL Injection

E anche

  • Come leggere il codice per le vulnerabilità di iniezione SQL .
risposta data 21.06.2018 - 20:02
fonte
4

Una misura di stopgap sarebbe quella di esaminare un firewall per applicazioni web (WAF) - ci sono alcune aziende che forniscono questo come servizio, e alcuni fornitori di cloud che hanno anche offerte. CloudFlare sembra offrirne uno, ho avuto un client che usa Incapsula e so che l'offerta AWS WAF ha alcuni set di regole gestiti 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 si farebbe per un CDN), e cerca cose che assomigliano a SQL tentativi di iniezione nei parametri. Non attaccherà tutti gli attacchi e potrebbe bloccare il traffico legittimo, ma è una correzione bandaid disponibile.

    
risposta data 21.06.2018 - 23:17
fonte
2

Per "non avere abbastanza sviluppatori", suppongo che intendi che alcune persone influenti nella tua organizzazione pensano che ci siano priorità più alte, quindi qualsiasi risorsa tu abbia sia dedicata a queste cose. Pertanto, la risoluzione del problema di sicurezza sta perdendo su altre cose in un'analisi costi-benefici.

Il tuo compito qui è quello di cambiare idea, tanto quanto è quello di implementare la correzione. Quantificare la posta in gioco: quale sarebbe il danno, sia in termini di denaro che di reputazione, di un'altra violazione? Potrebbero esserci leggi nella tua giurisdizione che richiedono a te di segnalare compromissioni dei dati dell'utente. Sarebbe imbarazzante? Potrebbero esserci resoconti dei media sulle cattive pratiche della tua organizzazione?

Pensa all'investimento per fissare la sicurezza come assicurazione. In retrospettiva, dopo aver saputo che il tuo edificio non ha bruciato per un periodo di dieci anni, potresti obiettare che i tuoi premi erano uno spreco. Ma tu e la tua organizzazione fate pagate l'assicurazione, perché affrontate un futuro incerto. È la gestione dei rischi.

Il rischio ha due fattori: probabilità e impatto. La probabilità di un'altra violazione è alta: sai che può essere ed è stato fatto almeno una volta. Se anche le potenziali conseguenze sono negative, dovresti aumentare la priorità di correggere le vulnerabilità della sicurezza.

    
risposta data 22.06.2018 - 05:28
fonte
0

Come tutti hanno menzionato, correggi il codice nel sito.

Puoi realizzare patch su un muro, ma fino a quando il muro non sarà costruito correttamente, qualsiasi patch sarà un problema da banda a bleeding ..

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

  • Correggi il tuo codice (dai più evidenti punti di iniezione all'ultimo parametro I.E Get) e usa le istruzioni preparate. come posso evitare sql injection in php

    • Puoi provare temporaneamente un WAF (IE ModSecurity ) finché non sarai in grado di sistemare le cose

    • Prova Forse una sorta di divieto IP su "persone che testano il sito" o il blocco di query non sicure che vengono fatte.

    • Se hai la possibilità di creare una schermata di accesso temporanea (sicura) di fronte finché non viene risolta.

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

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

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

    
risposta data 23.06.2018 - 13:53
fonte
0

La regola più importante è:

Utilizza 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 scomode da utilizzare, provocano un aumento di codice, inoltre possono essere spesso 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 davvero fare a modo suo e investire qualche sforzo per usare l'opzione non sicura! ...

Una soluzione molto migliore è un'API come Python dbapi. Ho scritto un equivalente php 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 foreach () può usare, quindi è molto più facile da usare rispetto a fetch () e cose del genere. Ancora più importante, il codice nascosto dietro questa API gestirà l'escape correttamente. Ciò rende le iniezioni SQL irrilevanti. Questo gestisce circa il 99% delle query se non si utilizza un ORM. Le query dinamiche (di solito la ricerca) avranno comunque bisogno di una gestione speciale, ma è comunque facile.

Se tieni a mente questa regola, ad un certo punto ti dovrai chiedere perché devi usare htmlspecialchars (), e perché la lingua non ha una funzione che renderebbe l'impostazione sicura (cioè, nessun XSS vulns) il più facile da usare? Perché oh perché? E questo è quando si rilascia PHP.

    
risposta data 23.06.2018 - 21:05
fonte
0

Oltre a tutte le ottime risposte finora, se vuoi affrontare il problema specifico di estrazione delle credenziali utente, puoi rifattorizzare il tuo database in modo che le password in una tabella separata con diritti di accesso rigorosi , simile al modo in cui i sistemi Unix li mettono in / etc / shadow.

Per verificare le credenziali, è necessaria una stored procedure che prenda la password inserita (o hash) come parametro e restituisca un valore booleano. In altre parole, si scarica il lavoro di verifica delle credenziali nel database e l'hash effettivo non lascia mai il database.

Ciò richiede un minimo di refactoring e risolve il problema immediato nella root, invece di una specifica iniezione SQL, lasciandoti vulnerabile al successivo.

    
risposta data 06.07.2018 - 12:17
fonte

Leggi altre domande sui tag