Dans Rails 3, je pourrais utiliser sanitize_sql_array
pour assainir le SQL brut lors des moments où une requête en SQL brut est nécessaire. Mais cela semble avoir été supprimé dans Rails 4, ou pas tellement supprimé, mais déplacé vers ActiveRecord :: Sanitization. Cependant, je ne sais pas comment appeler sanitize_sql_array
maintenant, alors quel est le meilleur moyen d'assainir le SQL brut dans Rails 4?
Je tiens à préciser que je parle ici d'une requête SQL brute complète, sans utiliser les modèles de Rail. Je suis conscient que ce n'est pas la meilleure pratique, c'est ce que je dois faire pour cette requête spécifique car elle ne peut pas être représentée par l'interface Nice ActiveRecord de Rails (faites-moi confiance, j'ai déjà essayé).
Voici un exemple d'appel, ce qui est évidemment plus simple que ce à quoi ressemble ma requête:
query = "SELECT * FROM users
LEFT OUTER JOIN posts ON users.id=posts.user_id
AND posts.topic_id = '#{topic.id}'"
# ^- Obviously bad and very vulnerable, this is what we're trying to fix
ActiveRecord::Base.connection.select_all(query)
Si vous avez vraiment besoin d'écrire du SQL brut, vous pouvez utiliser quote
pour le désinfecter:
conn = ActiveRecord::Base.connection
name = conn.quote("John O'Neil")
title = conn.quote(nil)
query = "INSERT INTO users (name,title) VALUES (#{name}, #{title})"
conn.execute(query)
Dans les documents Active Record , le meilleur moyen d'assainir une requête SQL est de eviter pour créer nos propres conditions sous forme de chaînes pures. En d'autres termes, insère les paramètres directement dans la requête, comme ceci:
User.find_by("user_name = '#{user_name}' AND password = '#{password}'")
et utilisez plutôt des conditions de tableau ou de hachage.
Conditions du tableau:
Client.where("orders_count = ? AND locked = ?", params[:orders], false)
Conditions de hachage:
Client.where(is_active: true)
Un exemple clarifiant:
class User < ActiveRecord::Base
# UNSAFE - susceptible to SQL-injection attacks
def self.authenticate_unsafely(user_name, password)
where("user_name = '#{user_name}' AND password = '#{password}'").first
end
# SAFE
def self.authenticate_safely(user_name, password)
where("user_name = ? AND password = ?", user_name, password).first
end
# SAFE
def self.authenticate_safely_simply(user_name, password)
where(user_name: user_name, password: password).first
end
end
Voici quelques références:
La méthode quote et les autres méthodes de nettoyage ActiveRecord::Base
sont obsolètes et ne faisaient jamais partie de l'API publique.
https://github.com/Rails/rails/issues/28947
Les méthodes officielles de désinfection sont
http://api.rubyonrails.org/classes/ActiveRecord/Sanitization/ClassMethods.html