2013-01-14 14 views
10

Nel nostro livello di accesso al DB abbiamo una creazione di query dinamica. Per esempio, abbiamo il metodo seguito per la costruzione di una parte di una clausola ORDER BY:Prevenzione dell'iniezione SQL nella clausola ORDER BY

protected string BuildSortString(string sortColumn, string sortDirection, string defaultColumn) 
{ 
    if (String.IsNullOrEmpty(sortColumn)) 
    { 
     return defaultColumn; 
    } 

    return String.Format("{0} {1}", sortColumn, sortDirection); 
} 

Il problema è, sortColumn e sortDirection entrambi provengono dall'esterno come stringhe, così naturalmente qualcosa deve essere fatto per prevenire eventuali attacchi di iniezione . Qualcuno ha idea di come questo possa essere fatto?

risposta

11

Se avete per affrontare nelle stringhe, poi bianco-lista è la soluzione migliore. Innanzitutto, sortDirection dovrebbe essere piuttosto banale per la white-list: un confronto senza distinzione tra maiuscole e minuscole confronta con "asc"/"desc" e si dovrebbe essere impostato. Per gli altri, la mia preferenza sarebbe quella di white-list per le colonne note , magari passando il previsto Type per i dati e la convalida. Ma a un pizzico assoluto, è possibile limitare con espressioni regolari per (dire) applicare tutti sono rigorosamente alfanumerici (nella gamma az, AZ, 0-9 - forse underscore se necessario) - e quindi aggiungere [], ovvero

return string.Format("[{0}] {1}", sortColumn, sortDirection); 

Ma: una rigida lista bianca di colonne note sarebbe molto meglio, come sarebbe un enume per la direzione.

+0

+1, aggiungerò un accento personale su "in un pizzico assoluto", che normalmente vuole whitelist in modo da avere il controllo su quali campi può essere ordinato da (o interrogato per quella materia). Lasciarlo al cliente per decidere significa che dovrai analizzare possibilmente più client per scoprire quali query ottimizzare. Ci sono stato, fatto questo, niente di divertente: -/ –

+1

Per la prima occhiata è possibile creare una white-list nel nostro caso. Faremo un tentativo, grazie Marco. – Andrei

0

È possibile eseguire questa operazione utilizzando una dichiarazione CASE di grandi dimensioni in cui si passa in base al nome e alla direzione della colonna passati. There's an SO answer on that here. Si sta andando ad essere alla ricerca di codice come:

SELECT 
    * 
FROM 
    My_Table 
WHERE 
    Whatever = @something 
ORDER BY 
    CASE @sort_order 
      WHEN 'ASC' THEN 
       CASE @order_by 
        WHEN 'surname' THEN surname 
        WHEN 'forename' THEN forename 
        WHEN 'fullname' THEN fullname 
        ELSE surname 
       END 
      ELSE '1' 
    END ASC, 
    CASE @sort_order 
      WHEN 'DESC' THEN 
       CASE @order_by 
        WHEN 'surname' THEN surname 
        WHEN 'forename' THEN forename 
        WHEN 'fullname' THEN fullname 
        ELSE surname 
       END 
      ELSE '1' 
    END DESC 
+2

Questo tipo di costruzione TSQL tende (nella mia esperienza) a produrre piani assolutamente orribili che semplicemente non funzionano. –

0

Soluzione: cmd.Parameters o EscapedString, ma io preferisco cmd.Parameters (lavorare sempre e si gode le eccezioni previste)

esempio:

cmd.CommandText = "SELECT UNIQUE_ID FROM userdetails WHERE USER_ID IN (?, ?)"; 
cmd.Parameters.Add("?ID1", OdbcType.VarChar, 250).Value = email1; 
cmd.Parameters.Add("?ID2", OdbcType.VarChar, 250).Value = email2; 

Using prepared statements with parameters helps to defend against SQL injection in most common cases, when you would otherwise interpolate untrusted content into a string and then execute the string as an SQL statement.

But a query parameter takes the place of a single value. You can't use a query parameter as a substitute for a dynamic table name, column name, list of values (e.g. for an IN() predicate), expressions, or SQL keywords.

For those cases, you can use techniques like filtering or whitelisting so you don't interpolate untrusted content into your SQL strings.

Filtering is where you strip out any characters that would cause trouble. If you know your dynamic column name should only be alphanumeric characters, then apply a filter to your variable before using it in SQL. Or else just reject a variable if it doesn't match a regular expression like /^[A-Za-z0-9]*$/

+3

@Destrictor Downvote non è il mio, ma la risposta non riguarda OP. Leggi nuovamente il titolo dell'OP "Previeni SQL Injection in ** ORDER BY clausola **" I parametri –

+0

non si applicano per 'order by' - che * non può * essere parametrizzato, a meno che non si faccia una query troppo complessa come la risposta di Wolfwyrd –

+1

@Destrictor no, non possono - almeno, non nello stesso modo."order by @ foo" è praticamente lo stesso di "order by 1" - è costante e non esegue alcun ordinamento. In quanto tale, è esplicitamente un errore di sintassi: "L'elemento SELECT identificato dal numero 1 di ORDER BY contiene una variabile come parte dell'espressione che identifica una posizione di colonna. Le variabili sono consentite solo quando si ordina da un'espressione che fa riferimento a un nome di colonna. –

1

Un'altra soluzione se è possibile cambiare il metodo di accettare int invece di string parametri.

protected string BuildSortString(int sortColumn, int sortDirection, string defaultColumn) 
{ 
    if (String.IsNullOrEmpty(sortColumn)) 
    { 
     return defaultColumn; 
    } 
//sortdirection 0-> "ASC" else "DESC" 
//sorColumn 1 for your firstcolumn, 2 for your second column etc. 
    return String.Format("{0} {1}", sortColumn, sortDirection==0? " ASC " : " DESC "); 
} 

Buona fortuna.

0

Si potrebbe fare qualcosa di simile:

public string BuildSortString(string sortColumn, SortDirection direction, string defaultColumn) 
{ 
    string sortDirection = direction.ToString(); 

    if (String.IsNullOrEmpty(sortColumn)) 
    { 
     return VerifyColumn(defaultColumn); 
    } 

    return String.Format("{0} {1}", VerifyColumn(sortColumn), sortDirection); 
} 

private string VerifyColumn(string column) 
{ 
    switch (column) // fill this with a whitelist of accepted columns 
    { 
     case "some_column": 
      return column; 
    } 

    return String.Empty; // the column must be invalid (do whatever you want here) 
} 

public enum SortDirection 
{ 
    ASC, DESC 
} 
Problemi correlati