Prevention of SQL injection via ruby script - mysql

i have created the following ruby script that logs into a mysql database and returns order information based on what username and password the user has entered. my question is how would i go about preventing sql injections? i know that the way it is written at the moment leaves it wide open to attacks but i am new to ruby and am not sure how to go about preventing this.
#!/usr/bin/ruby
#Import mysql module
require "mysql"
begin
#Establish connection to mysql database as the operator user.
connection = Mysql.real_connect("localhost", "operator", "", "rainforest")
#Allow Multi line statements
connection.set_server_option(Mysql::OPTION_MULTI_STATEMENTS_ON)
#Prompt user for username
puts "Please Enter Your Customer Username:"
#Get username entered and store to variable
username = gets.chomp
#Prompt user for password
puts "Please Enter Your Customer Password"
#Get password entered and store to variable
password = gets.chomp
#Specify SQL query that returns order if user entered data matches data held in customer table
customerQuery = connection.query("SELECT O.order_ID, O.date_ordered, C.customer_name, P.product_name
FROM orders As O
INNER JOIN customer As C ON O.customer_ID=C.customer_ID
INNER JOIN product As P ON O.product_ID=P.product_ID
WHERE C.customer_name = '" + name + "' AND C.customer_password = '" + password + "'")
#If query returns a row then user has entered correct login details
if customerQuery.num_rows > 0 then
#tell user they have successfully logged in
puts "User Successfully Authenticated: Hello " + username + ". Here are your orders: \n**********"
#Print all row data containing users order details to screen
while row = customerQuery.fetch_row do
puts row
puts "**********"
end
else
#if no rows return, user has entered incorrect details, inform them of this by printing to screen
puts "User Authentication Unsuccessful:Incorrect Username or Password, Please Try Again"
end
#close connection to database
connection.close
end

Use a prepared statement instead of string concatenation/interpolation:
p = connection.prepare(%q{
select o.order_id, o.date_ordered, c.customer_name, p.product_name
from orders as o
join customer as c on o.customer_id = c.customer_id
join product as p on o.product_id = p.product_id
where c.customer_name = ?
and c.customer_password = ?
})
customerQuery = p.execute(name, password)
if customerQuery.num_rows > 0
customerQuery.each do |row|
#...
end
else
#...
end
If you absolutely must use string interpolation for some bizarre reason, then use connection.quote:
customerQuery = connection.query(%Q{
select o.order_id, o.date_ordered, c.customer_name, p.product_name
from orders as o
join customer as c on o.customer_id = c.customer_id
join product as p on o.product_id = p.product_id
where c.customer_name = '#{connection.quote(name)}'
and c.customer_password = '#{connection.quote(password)}'
})
But really, don't do this unless you have no other choice. And in this case, you don't have to use string manipulation for this.

Related

How to optimize SQL in Python

first sorry my english :(
I am making a Python program accessing information from moodle. But the access to the server's sql is very slow, I needed to optimize the sql like the one below:
try:
query1 = "SELECT id FROM mdl_user WHERE username= ('%s')" % (self.searchuser2)
cursor.execute(query1)
linhas = cursor.fetchall()
for row in linhas:
self.userid = row[0]
# Pegando enrol_id do curso
query2 = "SELECT id FROM mdl_enrol WHERE courseid = %s AND enrol = 'manual'" % (self.rowidcourse)
cursor.execute(query2)
linhas = cursor.fetchall()
for row in linhas:
self.enrol_courseid = row[0]
# Inserindo o aluno e curso em mdl_user_enrolments
query3 = "INSERT INTO mdl_user_enrolments (status, enrolid, userid, timestart, timeend, timecreated, timemodified) VALUES(0, %s, %s, 1, 0, 1, 1)" % (
self.enrol_courseid, self.userid)
cursor.execute(query3)
mariadb_connection.commit()
# Pegando contex_id do curso e aluno
query4 = "SELECT id FROM mdl_context WHERE instanceid=%s AND contextlevel=50" % (self.rowidcourse)
cursor.execute(query4)
linhas = cursor.fetchall()
for row in linhas:
self.contexid = row[0]
# Inserindo aluno no curso
query5 = "INSERT INTO mdl_role_assignments (roleid,contextid,userid,timemodified) VALUES (5,%s,%s,2000)" \
% (self.contexid, self.userid)
cursor.execute(query5)
mariadb_connection.commit()
closedb()
tkinter.messagebox.showinfo("Muito bem!", "Aluno cadastrado com sucesso.", parent=self.register1)
It looks like you are enrolling all users into all courses? That's potentially a lot of data.
You are also getting all records from mdl_enrol for each loop of mdl_user.
And enrolid isn't the same as courseid. Enrolid is in mdl_enrol.
The code also doesn't check if the data already exists.
Also Moodle has lots of triggers that won't be activated by this code.
It might be better to have a look at Site Admin > Users > Upload users
https://docs.moodle.org/39/en/Upload_users#Enrolment_fields
This will allow you to enrol users into multiple courses.

issue with checking already existing values in table

I want to check of the values in my 3 textfield already exist in my table before proceeding further in my statement but it does not work in eclipse but work in heidisql? prepareStatement and resultset are properlt initislise at the top.
I already try using ? and preStatement.setString(1, get_status_update) but it gave me the same error result.
String get_status_update = stats_status_txta.getText();
String get_username= friend_username_txtf.getText();
String get_friendname= friend_list_txta.getText();
DB_connection db_connection = new DB_connection();
try{
if(get_username.length() < 3) {
JOptionPane.showMessageDialog(statusPanel,"You need to insert a username here","Post Lodge Status Error", JOptionPane.INFORMATION_MESSAGE);
} else if (get_status_update.length() < 3) {
JOptionPane.showMessageDialog(statusPanel,"Please insert the status update you wish to like","Post Lodge Status Error", JOptionPane.INFORMATION_MESSAGE);
} else {
String sql = " SELECT sut.status_update_id, up.user_id , fd.friend_id "
+ "FROM tb_logde_status_update as tsu "
+ "INNER JOIN status_update_tb as sut ON sut.status_update_id = tsu.status_update_id "
+ "INNER JOIN user_profile as up ON tsu.user_id = up.user_id "
+ "INNER JOIN friend_details as fd ON tsu.friend_id = fd.friend_id "
+ "WHERE sut.status_update_msg='"+get_status_update+"' AND up.username='"+get_username+"' AND fd.friend_username='"+get_friendname+"' ";
preStatement = db_connection.connect().prepareStatement(sql);
res = preStatement.executeQuery();
boolean send_logde_status = false;
while (res.next()) {
if(res.getString("status_update_msg").equalsIgnoreCase(get_status_update)
&& res.getString("username").equalsIgnoreCase(get_username)
&& res.getString("friend_username").equalsIgnoreCase(get_friendname)) {
JOptionPane.showMessageDialog(statusPanel, "Status update has already been like by you, choose another one!");
send_logde_status = true;
break; // Get out of the loop. No more need for it.
// Maybe the error is around here?
}
} ...
When I use the query directly from the database query it work!
SELECT sut.status_update_id, up.user_id , fd.friend_id
FROM tb_logde_status_update as tsu
INNER JOIN status_update_tb as sut ON sut.status_update_id = tsu.status_update_id
INNER JOIN user_profile as up ON tsu.user_id = up.user_id
INNER JOIN friend_details as fd ON tsu.friend_id = fd.friend_id
WHERE sut.status_update_msg="not hallo world" AND up.username="username" AND fd.friend_username="paul";
I am inserting the exactly values from my 3 textfields. I am getting the status_update_id, user_id, friend_id when i use the query from the database but not in my action listener button
Error: Column 'status_update_msg' not found.
Maybe the parameters are not exactly the same as the ones passed in the direct query, I would suggest the following:
Log the parameters values in console
Try using trim() and/or toLowerCase() if parameter values need to be in lower case only
Also, using setXXX() methods for preparedStatement is better approach than appending parameter values to a String query.

Db queries of OIM

DB query to check Account status of the user
DB query to check Entitlement status of the user
DB query to check Role and Access Policy mapping.
Please let me know if anyone have these queries?
For Account status
SELECT usr.usr_login,obj.obj_name,ost.ost_status
FROM orc, usr, obj, oiu, ost, obi WHERE orc.orc_key = oiu.orc_key AND oiu.usr_key = usr.usr_key AND oiu.ost_key = ost.ost_key
AND oiu.obi_key = obi.obi_key AND obi.obj_key = obj.obj_key AND obj.obj_name='ABC' order by usr.usr_login
Entitlement status of the user
select usr.usr_login,ENT_LIST.ent_display_name,
ENT_LIST.ent_value,ENT_ASSIGN.ent_status
from ENT_ASSIGN, usr, ENT_LIST where usr.usr_key = ent_assign.usr_key and
ENT_LIST.ent_list_key = ENT_ASSIGN.ent_list_key
and ENT_LIST.ent_value like 'ABC' order by usr.usr_login,ENT_DISPLAY_NAME;
Role and Access Policy mapping
select pol.pol_name, poc.poc_field_value from pol, poc where poc.pol_key = pol.pol_key AND poc.poc_field_name = 'ABC' order by pol.pol_name, poc.poc_field_value
To check Role assigned to User
select usr.usr_login, ugp.ugp_name from usg usg left outer join usr usr on (usg.usr_key = usr.usr_key)
left outer join ugp ugp on (ugp.ugp_key = usg.ugp_key)
where ugp_name ='ABC'

How to find records that are not joined with Waterline ORM

I am using the node.js framework, Sails JS, and its built-in ORM Waterline for a Tinder-like project.
I can't figure how I can write my query to get records that are not joined. In my case, when a user 'likes' or 'dislikes' another user's profile, I want the liked-profile to not show up again.
How do I accomplish this? This is what I've tried so far:
Cat.query('select cat.* from cat left outer join vote on cat.id = vote.owner where vote.owner is null AND cat.id !='+req.session.User.id, function (err, results) {
if (err) return res.serverError(err);
res.send('Yes');
console.log(results);
});
If I got you right, Cat is user profile?
So, we need profiles which:
Don't belong to current user (cat.id !== req.session.User.id)
Not liked or disliked by current user.
var query = 'select cat.* ' +
' from cat left join vote on' +
// joining votes for current user
' cat.id = vote.catId and vote.owner = ' + req.session.User.id +
' where' +
// filtering out the Cat with current user Id (if needed)
' cat.id <> ' + req.session.User.id +
' and' +
// leaving only records with empty vote id(meaning there's no corresponding vote record)
' vote.id is null';
Pure SQL for more crear view:
select cat.* from cat left join vote on
cat.id = vote.catId and vote.owner = :userId
where
cat.id <> :userId
and
vote.id is null
We selecting all records from cat table joining votes made for them by current user. And then leaving only the records where the votes are missing, and where id <> current user Id

How to use Boolean logic in a mySQL SELECT query

How can I check if email = '$e' or username = '$e' inside my MySQL query.
Here is my MySQL query so far.
"SELECT user_id FROM users WHERE (email = '$e' AND pass=SHA1('$p'))"
If you want to modify you existing query so that it works even if $e matches username, you can do:
SELECT user_id
FROM users
WHERE (email = '$e' OR username = '$e') AND pass=SHA1('$p')