Prevenzione dell’iniezione SQL nella clausola ORDER BY

Nel nostro livello di accesso ai DB abbiamo una creazione di una query dynamic. Ad esempio, abbiamo il seguente metodo per build una parte di una 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 vengono entrambi da fuori come stringhe, quindi, naturalmente, si dovrebbe fare qualcosa per prevenire possibili attacchi di iniezione. Qualcuno ha idea di come questo possa essere fatto?

Se devi occuparti di stringhe, allora la tua offerta migliore è la white-listing. In primo luogo, sortDirection dovrebbe essere piuttosto banale per la white-list: un case-insensitive confronta con "asc" / "desc" e dovresti essere impostato. Per gli altri, la mia preferenza sarebbe quella di white-list per le colonne conosciute , magari passando il Type previsto per i dati e la convalida. Ma a un pizzico assoluto, si può limitare con espressioni regolari per (dire) applicare tutte sono strettamente alfanumeriche (nell’intervallo az, AZ, 0-9 – forse underscore se necessario) – e quindi aggiungere [] , cioè

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

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

Un’altra soluzione se è ansible modificare il metodo per accettare int invece di parametri di string .

 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 "); } 

In bocca al lupo.

È ansible farlo utilizzando una dichiarazione CASE di grandi dimensioni in cui si passa in base al nome e alla direzione della colonna passati. C’è una risposta SO su questo qui . Stai andando a guardare il 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 

Soluzione: cmd.Parameters o EscapedString , ma preferisco cmd.Parameters (funziona sempre e ti piacciono 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; 

L’utilizzo di istruzioni preparate con parametri aiuta a difendersi dall’iniezione SQL nei casi più comuni, quando altrimenti si interpolerebbe il contenuto non affidabile in una stringa e quindi si eseguirà la stringa come un’istruzione SQL.

Ma un parametro di query prende il posto di un singolo valore. Non è ansible utilizzare un parametro di query come sostituto per un nome di tabella dinamico, un nome di colonna, un elenco di valori (ad esempio per un predicato IN ()), espressioni o parole chiave SQL.

In questi casi, puoi utilizzare tecniche come il filtro o la whitelist in modo da non interpolare il contenuto non affidabile nelle stringhe SQL.

Il filtraggio è il punto in cui estrai i caratteri che potrebbero causare problemi. Se si conosce il nome della colonna dynamic dovrebbe essere solo caratteri alfanumerici, quindi applicare un filtro alla variabile prima di utilizzarla in SQL. Oppure rifiuta semplicemente una variabile se non corrisponde ad un’espressione regolare come / ^ [A-Za-z0-9] * $ /

Potresti fare qualcosa del genere:

 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 }