I am using Ruby on Rails 3.2.2 and I am running the following raw SQL:
sql = "INSERT INTO articles (`title`, `user_id`) VALUES #{inserts.join(", ")}"
ActiveRecord::Base.connection.execute(sql)
However, I would like to use the Ruby on Rails exec_insert method but there isn't good documentation about that. So, how can I use the exec_insert method so to make the same thing I stated above (maybe using something like Article.connection.exec_insert(...))?
You can use exec_query for this
ActiveRecord::Base.connection().exec_query('INSERT INTO articles(title, user_id) VALUES($1, $2)', 'someQueryName', [[nil, title], [nil, user_id]])
Please note that I have used and tested $1, $2 for Postgres only as $1,$2 is the convention used for binding prepare query in postgres.
It maybe different for MySql & other databases. For Mysql I think it should be ? instead of $1, $2 etc, it depends on how the database offers binding
Also you might have to set prepare_query: true for some. Refer -http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#exec_query
exec_insert is an internal method and probably isn't what you want here. What you have should be fine.
If you're really set on using it, and need examples, the test suite possibly the best place to find them. One example is here.
Related
I was solving one of TryHackMe's rooms about SQL injection.But I couldn't figured out one thing that came to my mind and after spending lots of time I thought it's best to ask that question here. In the room there is a machine to deploy, after deployed machine it gave me an interface(webapp) that takes inputs from me like so :
And if you give it a value like test. It returns following output:
When I saw it, I thought it was an easy SQLi question so I tried most basic SQLi payloads for common dbms like so:
' ; sleep(1) --
' or 1=1 -- ...
But none of them worked and returned me an error message like that:
After that failure, I run sqlmap and it found 2 types of SQLi payload with following payloads:
Then I realized that in time based SQLi, sqlmap used ||. Then I tried to send '|| (select sleep(2)) -- . And it worked. Now my question is why my first payload(' ; select sleep(2) -- ) didn't work, but this one worked ?
By default, MySQL query interfaces do not support multiple queries separated by semicolon. To get that, the application would have to explicitly request this feature to be enabled when it connects to the database. There's a connect option for that.
So by default, any type of SQL injection that works by trying to append a malicious query after a semicolon doesn't work.
But an SQL injection that works by modifying an expression in the single query can still work.
I have a portion of a MySQL query which is designed to save a password using SHA512-CRYPT:
SELECT ENCRYPT('firstpassword', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16)))
I need to port the application to use PostgreSQL, and as such, the statement is not compatible.
My attempt in PostgreSQL is like so:
SELECT CRYPT('firstpassword'::text, CONCAT('$6$', SUBSTRING(ENCODE(DIGEST(RANDOM()::text , 'sha1'), 'hex') FROM '.{16}$')))
When tested in component parts, each of these implementations appear identical, but as completed statements, the output differs.
I have found that the CONCAT statements (that generate the salt) appear to provide identical output.
If I try comparing the output of CRYPT or ENCRYPT using simple plaintext words, the output is identical. However, if I combine it with the output of a salt, the output differs;
MySQL:
SELECT ENCRYPT( 'firstpassword', '$6$ae73a5ca7d3e5b11' )
Produces: $6$ae73a5ca7d3e5b11$v/RbcEEx4VR37VMUF6gBnPNo2ptSyU...
PostgreSQL:
SELECT CRYPT('firstpassword'::text, '$6$ae73a5ca7d3e5b11'::text)
Produces: $6eTK2KpfoaQM
Can someone explain why these statements are diverging or suggest a better way to implement this MySQL query?
They diverge because they use different encryption algorithms.
The first thing you want to do is to get very familiar with the pg_crypto documentation. See http://www.postgresql.org/docs/9.2/static/pgcrypto.html
My suspicion is that you probably want to switch from something like encrypt/crypt to the use of SHA-2 for the actual password hashing so you can specifically control the algorithms and ensure compatibility on both sides.
SHA512-CRYPT is not supported by PostgreSQL core or the pgcrypto extension shipped with the main sources. The crypt function shown in the question comes from pgcrypto and does only support bf, md5, des and xdes (see "supported algorithm" in the documentation).
But you may use the shacrypt extension:
test=# create extension shacrypt ; -- (after installing from the sources)
CREATE EXTENSION
test=# select sha512_crypt('firstpassword', '$6$ae73a5ca7d3e5b11' );
sha512_crypt
------------------------------------------------------------------------------------------------------------
$6$ae73a5ca7d3e5b11$v/RbcEEx4VR37VMUF6gBnPNo2ptSyU3ys1sg6i8hhBrcfBeLY6hpsfvXR67bwwjMainpPEaLkYV6eO0ow0xVH.
which gives the same result as MySQL's SELECT ENCRYPT( 'firstpassword', '$6$ae73a5ca7d3e5b11' )
I have the following code that run on heroku inside a controller that intermittently fails. It's a no-brainer that it should work to me, but I must be missing something.
#artist = Artist.find(params[:artist_id])
The parameters hash looks like this:
{"utf8"=>"������",
"authenticity_token"=>"XXXXXXXXXXXXXXX",
"password"=>"[FILTERED]",
"commit"=>"Download",
"action"=>"show",
"controller"=>"albums",
"artist_id"=>"62",
"id"=>"157"}
The error I get looks like this:
ActiveRecord::StatementInvalid: Mysql::Error: : SELECT `artists`.* FROM `artists` WHERE `artists`.`id` = ? LIMIT 1
notice the WHEREartists.id= ? part of the statement? It's trying to find an ID of QUESTION MARK. Meaning Rails is not passing in the params[:artist_id] which is obviously in the params hash. I'm at complete loss.
I get the same error on different pages trying to select the record in a similar fashion.
My environment: Cedar Stack on Heroku (this only happens on Heroku), Ruby 1.9.3, Rails 3.2.8, files being hosted on Amazon S3 (though I doubt it matters), using the mysql gem (not mysql2, which doesn't work at all), ClearDB MySQL database.
Here's the full trace.
Any help would be tremendously appreciated.
try sql?
If it's just this one statement, and it's causing production problems, can you omit the query generator just for now? In other words, for very short term, just write the SQL yourself. This will buy you a bit of time.
# All on one line:
Artist.find_by_sql
"SELECT `artists`.* FROM `artists`
WHERE `artists`.`id` = #{params[:artist_id].to_i} LIMIT 1"
ARel/MySQL explain?
Rails can help explain what MySQL is trying to do:
Artist.find(params[:artist_id]).explain
http://weblog.rubyonrails.org/2011/12/6/what-s-new-in-edge-rails-explain/
Perhaps you can discover some kind of difference between the queries that are succeeding vs. failing, such as how the explain uses indexes or optimizations.
mysql2 gem?
Can you try changing from the mysql gem to the mysql2 gem? What failure do you get when you switch to the mysql2 gem?
volatility?
Perhaps there's something else changing the params hash on the fly, so you see it when you print it, but it's changed by the time the query runs?
Try assigning the variable as soon as you receive the params:
artist_id = params[:artist_id]
... whatever code here...
#artist = Artist.find(artist_id)
not the params hash?
You wrote "Meaning Rails is not passing in the params[:artist_id] which is obviously in the params hash." I don't think that's the problem-- I expect that you're seeing this because Rails is using the "?" as a placeholder for a prepared statement.
To find out, run the commands suggested by #Mori and compare them; they should be the same.
Article.find(42).to_sql
Article.find(params[:artist_id]).to_sql
prepared statements?
Could be a prepared statement cache problem, when the query is actually executed.
Here's the code that is failing-- and there's a big fat warning.
begin
stmt.execute(*binds.map { |col, val| type_cast(val, col) })
rescue Mysql::Error => e
# Older versions of MySQL leave the prepared statement in a bad
# place when an error occurs. To support older mysql versions, we
# need to close the statement and delete the statement from the
# cache.
stmt.close
#statements.delete sql
raise e
end
Try configuring your database to turn off prepared statements, to see if that makes a difference.
In your ./config/database.yml file:
production:
adapter: mysql
prepared_statements: false
...
bugs with prepared statements?
There may be a problem with Rails ignoring this setting. If you want to know a lot more about it, see this discussion and bug fix by Jeremey Cole and Aaron: https://github.com/rails/rails/pull/7042
Heroku may ignore the setting. Here's a way you can try overriding Heroku by patching the prepared_statements setup: https://github.com/rails/rails/issues/5297
remove the query cache?
Try removing the ActiveRecord QueryCache to see if that makes a difference:
config.middleware.delete ActiveRecord::QueryCache
http://edgeguides.rubyonrails.org/configuring.html#configuring-middle
try postgres?
If you can try Postgres, that could clear it up too. That may not be a long term solution for you, but it would isolate the problem to MySQL.
The MySQL statement is obviously wrong, but the Ruby code you mentioned would not produce it. Something is wrong here, either you use a different Ruby code (maybe one from a before_filter) or pass a different parameter (like params[:artist_id] = "?"). Looks like you use nested resources, something like Artist has_many :albums. Maybe the #artist variable is not initialized correctly in the previous action, so that params[:artist_id] has not the right value?
What would be the equivalent raw sql for the following:
def index:
Emails.objects.create(email=request.POST['invite_email'])
I have this so far, but I can't quite get the quotations working --
cursor = connection.cursor()
cursor.execute("insert into splash_emails (id, email) values ('0','request.POST[invite_email]')")
transaction.commit_unless_managed()
What would be correct way to write this, and is this the simplest way to perform raw sql?
If you ever want to see the queries django is using you can do:
emails = Emails.objects.create(email=request.POST['invite_email'])
print emails.query
It's a bit verbose, but you'll get the gist.
I think after reading the Django cookbook chapter on Security, you'll have a good idea on how to execute raw sql AND execute it safely.
I am using prepared statements with mysqli(); to insert and retrieve data on my website also i used bind_param so i don't add variables directly into the query.I used strip_tags to clean any inputs what else should i look out for ?
Don't use strip_tags() on database input: use htmlentites() (or urlencode() where appropriate) on browser output.