Le procedure memorizzate impediscono l'iniezione di SQL?


83

È vero che le procedure memorizzate impediscono gli attacchi SQL injection contro i database PostgreSQL? Ho fatto una piccola ricerca e ho scoperto che SQL Server, Oracle e MySQL non sono sicuri contro l'iniezione di SQL anche se utilizziamo solo procedure memorizzate. Tuttavia, questo problema non esiste in PostgreSQL.

L'implementazione della procedura memorizzata nel core PostgreSQL impedisce gli attacchi SQL injection o è qualcos'altro? O PostgreSQL è anche suscettibile all'iniezione SQL anche se utilizziamo solo stored procedure? In tal caso, mostrami un esempio (ad esempio libro, sito, carta, ecc.).


4
Stranamente, le risposte migliori qui sono principalmente OT che si occupano di SQL Server mentre la domanda riguarda Postgres . Ecco una risposta correlata per Postgres: dba.stackexchange.com/questions/49699/… . Ce ne sono altri, prova una ricerca: dba.stackexchange.com/…
Erwin Brandstetter,

@ErwinBrandstetter la domanda originale non è stata taggata (dall'OP) con Postgres ed è stata - e ancora - menziona molti altri DBMS. Immagino che sia la ragione per cui le varie risposte si concentrano su altri DBMS. Ti suggerisco di aggiungerne un altro incentrato su Postgres.
ypercubeᵀᴹ

@ ypercubeᵀᴹ: aggiungerò una risposta qui quando trovo il tempo. Nel frattempo ho aggiornato dba.stackexchange.com/questions/49699/… a più chiaro e completo.
Erwin Brandstetter,

Risposte:


71

No, le stored procedure non impediscono l'iniezione di SQL. Ecco un esempio reale (da un'app interna creata da qualcuno dove lavoro) di una procedura memorizzata che purtroppo consente l'iniezione SQL:

Questo codice server SQL:

CREATE PROCEDURE [dbo].[sp_colunmName2]   
    @columnName as nvarchar(30),
    @type as nvarchar(30), 
    @searchText as nvarchar(30)           
AS
BEGIN
    DECLARE @SQLStatement NVARCHAR(4000)
    BEGIN
        SELECT @SQLStatement = 'select * from Stations where ' 
            + @columnName + ' ' + @type + ' ' + '''' + @searchText + '''' 
        EXEC(@SQLStatement)
    END      
END
GO

approssimativamente equivalente a postgres:

CREATE or replace FUNCTION public.sp_colunmName2 (
    columnName  varchar(30),
    type varchar(30), 
    searchText  varchar(30) ) RETURNS SETOF stations LANGUAGE plpgsql            
AS
$$
DECLARE SQLStatement VARCHAR(4000);
BEGIN
    SQLStatement = 'select * from Stations where ' 
            || columnName || ' ' || type || ' ' || ''''|| searchText || '''';
    RETURN QUERY EXECUTE  SQLStatement;
END
$$;

L'idea dello sviluppatore era quella di creare una procedura di ricerca versatile, ma il risultato è che la clausola WHERE può contenere tutto ciò che l'utente desidera, consentendo una visita da piccoli tavoli Bobby .

Non importa se usi istruzioni SQL o stored procedure. Ciò che conta è se il tuo SQL utilizza parametri o stringhe concatenate. I parametri impediscono l'iniezione SQL; stringhe concatenate consentono l'iniezione SQL.


46

Gli attacchi SQL Injection sono quelli in cui l'input non attendibile viene aggiunto direttamente alle query, consentendo all'utente di eseguire in modo efficace codice arbitrario, come illustrato in questo fumetto canonico XKCD.

Quindi, otteniamo la situazione:

userInput = getFromHTML # "Robert ') Elimina gli studenti della tabella; -"

Query = "Seleziona * dagli studenti in cui studentName =" + userInput

Le Stored procedure sono, in generale, buone difese contro gli attacchi SQL injection perché i parametri in arrivo non vengono mai analizzati.

In una procedura memorizzata, nella maggior parte dei DB (e programmi, non dimenticare che le query precompilate contano come procedure memorizzate) sono simili alle seguenti:

 

creare Stored procdure foo (
seleziona * dagli studenti in cui studentName =: 1
);

Quindi, quando il programma desidera accedere, chiama foo(userInput)e recupera felicemente il risultato.

Una stored procedure non è una difesa magica contro SQL-Injection, come le persone sono abbastanza in grado di scrivere male stored procedure. Tuttavia, le query precompilate, archiviate nel database o nel programma, sono molto più difficili da aprire falle di sicurezza se si capisce come funziona SQL-Injection.

Puoi leggere di più su SQL-Injection:


29

Sì, in una certa misura.
Le stored procedure da sole non impediranno l'iniezione di SQL.

Vorrei prima citare SQL Injection da OWASP

Un attacco di iniezione SQL consiste nell'inserimento o "iniezione" di una query SQL tramite i dati di input dal client all'applicazione. Un exploit di SQL injection riuscito può leggere i dati sensibili dal database, modificare i dati del database (Inserisci / Aggiorna / Elimina), eseguire operazioni di amministrazione sul database (come arrestare il DBMS), recuperare il contenuto di un determinato file presente nel file DBMS sistema e in alcuni casi impartire comandi al sistema operativo. Gli attacchi di iniezione SQL sono un tipo di attacco di iniezione, in cui i comandi SQL vengono immessi nell'input sul piano dati per effettuare l'esecuzione di comandi SQL predefiniti.

È necessario disinfettare gli input dell'utente e non concatenare le istruzioni SQL, anche se si utilizza la stored procedure.

Jeff Attwood ha spiegato le conseguenze della concatenazione di sql in " Dammi SQL parametrizzato o dammi la morte "

Di seguito è riportato l'interessante fumetto che mi viene in mente ogni volta che sento SQL Injection testo alternativo penso che tu abbia capito il punto :-)

Dai un'occhiata al Cheat Sheet di SQL Injection Prevention , i metodi di prevenzione sono ben spiegati ...


12

La concatenazione di stringhe è la causa dell'iniezione SQL. Questo è evitato usando la parametrizzazione.

Le procedure memorizzate aggiungono un ulteriore livello di sicurezza applicando una sintassi non valida quando si concatena, ma non sono "più sicure" se si usa, diciamo, SQL dinamico in esse.

Quindi, il codice sopra riportato è causato dalla concatenazione di queste stringhe

  • exec sp_GetUser '
  • x' AND 1=(SELECT COUNT(*) FROM Client); --
  • ' , '
  • monkey
  • '

Questo dà sintassi non valida, per fortuna

Parametrizzare darebbe

exec sp_GetUser 'x'' AND 1=(SELECT COUNT(*) FROM Client); --' , 'monkey'

Questo significa

  • @UserName = x' AND 1=(SELECT COUNT(*) FROM Client); --
  • @Password = monkey

Ora, nel codice sopra non otterrai righe perché presumo che tu non abbia utenti x' AND 1=(SELECT COUNT(*) FROM Client); --

Se il proc memorizzato appare così (usando SQL dinamico concatenato ), la tua chiamata proc memorizzata parametrizzata consentirà comunque l'iniezione SQL

...
SET @sql = 'SELECT userName from users where userName = ''' + 
               @UserName + 
               ''' and userPass = ''' +
               @Password +
               ''''
EXEC (@sql)
....

Quindi, come dimostrato, la concatenazione di stringhe è il principale nemico dell'iniezione SQL

Le procedure memorizzate aggiungono incapsulamento, gestione delle transazioni, autorizzazioni ridotte, ecc., Ma possono comunque essere abusate per l'iniezione SQL.

Puoi consultare Stack Overflow per ulteriori informazioni sulla parametrizzazione


10

"Attacchi SQL injection accadere quando l'input dell'utente è correttamente codificato. Tipicamente, l'input dell'utente viene alcuni dati inviati dall'utente con la sua interrogazione, ossia quei valori nei $_GET, $_POST, $_COOKIE, $_REQUESTo $_SERVERmatrici. Tuttavia, l'input dell'utente possono anche venire da una varietà di altri fonti, come socket, siti Web remoti, file, ecc. Pertanto, dovresti davvero considerare tutto tranne le costanti (come 'foobar') come input dell'utente . "

Di recente ho studiato a fondo questo argomento e vorrei condividere con altri materiale abbastanza interessante, rendendo così questo post più completo e istruttivo per tutti.



Da YouTube


Da Wikipedia


Da OWASP


Dal manuale di PHP


Da Microsoft e Oracle


Stack Overflow


Scanner per iniezione SQL


2

Le procedure memorizzate non impediscono magicamente l'iniezione di SQL, ma rendono molto più semplice prevenirlo. Tutto quello che devi fare è qualcosa di simile al seguente (esempio Postgres):

CREATE OR REPLACE FUNCTION my_func (
  IN in_user_id INT 
)
[snip]
  SELECT user_id, name, address FROM my_table WHERE user_id = in_user_id; --BAM! SQL INJECTION IMMUNE!!
[snip]

Questo è tutto! Il problema si presenta solo quando si forma una query tramite concatenazione di stringhe (ovvero SQL dinamico) e anche in quei casi potresti essere in grado di legare! (Dipende dal database.)

Come evitare l'iniezione SQL nella query dinamica:

Passaggio 1) Chiediti se hai davvero bisogno di una query dinamica. Se stai mettendo insieme le stringhe solo per impostare l'input, probabilmente stai sbagliando. (Esistono eccezioni a questa regola: un'eccezione è per la segnalazione di query su alcuni database, potresti avere problemi di prestazioni se non lo costringi a compilare una nuova query con ogni esecuzione. Ma cerca questo problema prima di saltare a quello. )

Passaggio 2) Ricercare il modo corretto di impostare la variabile per il proprio RDBMS. Ad esempio, Oracle ti consente di fare quanto segue (citando dai loro documenti):

sql_stmt := 'UPDATE employees SET salary = salary + :1 WHERE ' 
           || v_column || ' = :2';
EXECUTE IMMEDIATE sql_stmt USING amount, column_value; --INJECTION IMMUNE!!

Qui non stai ancora concatenando l'input. Stai vincolando in modo sicuro! Evviva!

Se il tuo database non supporta qualcosa di simile a quanto sopra (speriamo che nessuno di loro sia ancora così male, ma non sarei sorpreso) - o se devi ancora concatenare il tuo input (come nel caso "a volte" di segnalazione di query come Ho accennato sopra), quindi è necessario utilizzare una corretta funzione di escape. Non scriverlo da solo. Ad esempio postgres fornisce la funzione quote_literal (). Quindi avresti eseguito:

sql_stmt := 'SELECT salary FROM employees WHERE name = ' || quote_literal(in_name);

In questo modo se in_name è qualcosa di subdolo come '[snip] o 1 = 1' (la parte "o 1 = 1" significa selezionare tutte le righe, permettendo all'utente di vedere gli stipendi che non dovrebbe!), Allora quote_literal salva il tuo sedere di rendendo la stringa risultante:

SELECT salary FROM employees WHERE name = '[snip] or 1=1'

Nessun risultato verrà trovato (a meno che tu non abbia alcuni dipendenti con nomi davvero strani.)

Questa è la sostanza! Ora lascia che ti lasci un link a un post classico del guru Oracle Tom Kyte sull'argomento SQL Injection, per riportare il punto a casa: Linky


Non dimenticare di menzionare quote_ident(), ma in generale il modo più semplice per scrivere SQL dinamico a prova di iniezione è utilizzare format()e utilizzare i segnaposto %Iper identificatori e %Lvalori letterali. In questo modo l'SQL è molto più leggibile rispetto alla versione equivalente che utilizza ||e alle quote_....()funzioni
a_horse_with_no_name
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.