Mysql
 sql >> Database >  >> RDS >> Mysql

Nome della colonna dinamica utilizzando istruzione preparata + query sql con variabile contenente 's

Giusto. Non possiamo fornire identificatori come parametri di associazione. Il nome della colonna deve essere parte del testo SQL.

Possiamo incorporare dinamicamente il nome della colonna nel testo SQL con qualcosa del genere:

  sql = "UPDATE diseaseinfo"
      + " SET `" + colname + "` = ?"
      + " WHERE companyname = 'mycom' AND diseaseName = ?";

E fornisci i valori per i due parametri di associazione rimanenti

  preparedStmt.setString(1, attrData);
  preparedStmt.setString(2, medname);

E hai assolutamente ragione sull'essere preoccupato per SQL injection.

Fornito come valori di rilegatura, virgolette singole nei valori di attrData e medname non sarà un problema, in termini di SQL injection.

Ma l'esempio che ho fornito è vulnerabile incorporando il colname variabile nel testo SQL, se non abbiamo alcuna garanzia che colname è "sicuro" da includere nella dichiarazione.

Quindi dobbiamo fare l'assegnazione di un valore a colname "sicuro".

Diversi approcci che possiamo usare per farlo. Il più sicuro sarebbe un approccio "lista bianca". Il codice può garantire che solo determinati valori "sicuri" consentiti vengano assegnati a colname , prima di colname viene incluso nel testo SQL.

Come semplice esempio:

  String colname;
  if (attributes.equals("someexpectedvalue") {
      colname = "columnname_to_be_used";
  } else if (attributes.equals("someothervalid") {
      colname = "valid_columname";
  } else {
     // unexpected/unsupported attributes value so
     // handle condition or throw an exception 
  }

Un approccio più flessibile consiste nell'assicurarsi che un carattere di backtick non appaia in colname . Nell'esempio, il valore di colname viene escape racchiudendolo in backtick. Quindi, fintanto che un carattere backtick non appare in colname , eviteremo che un valore fornito venga interpretato come qualcosa di diverso da un identificatore.

Per un approccio più generico (e complicato) all'utilizzo di caratteri di backtick codificati, potremmo prendere in considerazione l'utilizzo di supportsQuotedIdentifiers e getIdentifierQuoteString metodi di java.sql.DatabaseMetaData classe.

(Nel codice OP, non vediamo il tipo di dati dei contenuti di attributes . Vediamo una chiamata a un metodo chiamato replace , e gli argomenti forniti a tale proposito. Supponendo che attributes è una stringa, e dovrebbe essere un nome di colonna, non è affatto chiaro perché dovremmo avere "spazio virgolette singole" nella stringa o perché dobbiamo rimuoverlo. A parte questa menzione, questa risposta non affronta questo.)