En général, vous ne devriez pas utiliser l'interpolation de chaîne pour construire des requêtes SQL. Cela vous laissera la porte ouverte aux attaques SQL injection, dans lesquelles quelqu'un fournit une entrée avec un guillemet fermant, suivi d'une autre requête. Par exemple, en utilisant votre exemple:
>> val = '7; DROP TABLE users;'
=> "7; DROP TABLE users;"
>> myQuery = "select * from t where t.val = \#{val}"
=> "select * from t where t.val = \#{val}"
>> eval "\"#{myQuery}\""
=> "select * from t where t.val = 7; DROP TABLE users;"
Même sans entrée malveillant, vous pouvez simplement exécuter accidentellement le code que vous n'êtes pas l'intention de, si quelqu'un instance inclus guillemets dans leur entrée.
Il est également généralement recommandé d'éviter d'utiliser eval
sauf en cas d'absolue nécessité; il est possible que si vous avez un bogue dans votre programme, quelqu'un puisse exécuter du code arbitraire en le faisant passer à eval
, et cela rend le code moins maintenable puisque certains de vos codes source seront chargés à partir d'endroits autres que votre arborescence source habituelle.
Alors, comment faites-vous cela à la place? Les API de base de données incluent généralement une commande prepare
, qui peut préparer l'exécution d'une instruction SQL. Dans cette instruction, vous pouvez inclure ?
caractères, qui représentent les paramètres qui peuvent être substitués dans cette instruction. Vous pouvez ensuite appeler le execute
sur l'instruction, en passant des valeurs pour ces paramètres, et ils seront exécutés en toute sécurité, sans que personne ne puisse exécuter une partie arbitraire de SQL.
Voici comment cela fonctionnerait dans votre exemple. Cela suppose que vous utilisez this MySQL/Ruby module; Si vous en utilisez un autre, il aura probablement une interface similaire, bien que ce ne soit pas exactement la même chose.
>> val = 7
>> db = Mysql.new(hostname, username, password, databasename)
>> query = db.prepare("select * from t where t.val = ?")
>> query.execute(val)