am reading data from a user-supplied CSV file of unknown number of rows. I iterate through the rows and rather than individually insert each row individually into the database (potentially a performance hurting large number of inserts), I concatenate the values into a single string:

insert_values += ", (#{params[:quantity]}, #{'#{params[:name]}', '#{Time.now.to_s(:db)}')"

I then build the full sql query:

sql = "INSERT INTO `my_table` (`quantity`, `name`, `created_at`) VALUES"+insert_values

Finally, I execute it:

ActiveRecord::Base.connection.execute(sql)

I want to make the data safe from malicious injection. What is the best way to do this?

有帮助吗?

解决方案 3

Thanks for all the helpful advice which led me down my final path. I ended up changing my string to an array of values to take advantage of Rails built-in method, sanitize_sql_array after reading another post.

placeholders = []
insert_values = []

csvrow.each do |row|
  placeholders << (?,?,?)
  insert_values << params[:quantity] << #{params[:name]} << {Time.now.to_s(:db)
end

query_string = "INSERT INTO `my_table` (`quantity`, `name`, `created_at`) VALUES #{placeholders.join(", ")}"] + insert_values
sql = ActiveRecord::Base.send(:sanitize_sql_array, query_string)
ActiveRecord::Base.connection.execute(sql)

其他提示

If you're going to do this then you need to take the time to escape every field going into the db using AR's underlying connection escape methods. Otherwise you are just asking for trouble.

Or... use something else that is meant for doing a lot of volume, but still handles the escaping for you... https://github.com/zdennis/activerecord-import

You could consider using MySQL LOAD DATA INFILE syntax to insert your CSV data. It is optimized for upload and doesn't require you to manually build an injection-prone query string.

Here is link to MySQL docs:

http://dev.mysql.com/doc/refman/5.6/en/load-data.html

LOAD DATA [LOCAL] INFILE '/path/to/data.csv'
INTO table
FIELDS TERMINATED BY ',' ENCLOSED BY '' ESCAPED BY '\'
LINES TERMINATED BY '\n'

Note use LOCAL if app server and database are on different machines. you might need to change field and line settings based on the format of your CSV.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top