How do I prevent SQL injection when using the LIKE operator? - mysql

I am building a website using Node and the node-mysql package.
app.get('/api/tags', function(req, res) {
var term = req.query.term;
var query =
'SELECT \
t.tagName \
FROM tags t \
JOIN screencastTags st \
ON st.tagName = t.tagName \
JOIN screencasts s \
ON s.screencastId = st.screencastId \
WHERE s.status = \'approved\' AND t.tagName LIKE \'%' + term + '%\' \
GROUP BY t.tagName \
LIMIT 5';
connection.queryAsync(query).spread(function(tags) {
tags = tags.map(function(tag) { return tag.tagName });
res.send(tags);
})
})
Here I use a value from the query string - term - to return a list of tags.
My question is: How do I prevent against SQL injection when I am using the LIKE operator?
I tried
var query =
'SELECT \
t.tagName \
FROM tags t \
JOIN screencastTags st \
ON st.tagName = t.tagName \
JOIN screencasts s \
ON s.screencastId = st.screencastId \
WHERE s.status = \'approved\' AND t.tagName LIKE \'%' + conneciton.escape(term) + '%\' \
GROUP BY t.tagName \
LIMIT 5';
But that produces invalid SQL.

Try to never build an sql request by concatenation. It indeed always increases the risk of the SQL injection footprint.
A placeholder should work even with the LIKE condition.
var sql = '... LIKE ? GROUP BY ...';
connection.query(sql, ['%' + term + '%'], function(err, res) {})
A prepared statement would even be better for security concerns. you should read https://github.com/felixge/node-mysql/#escaping-query-values

Related

issues populating with_expression() in a subquery

I'm able to populate with_expression() just fine when I run a query, but when instead I convert that query into a subquery, it appears with_expression() is not working as expected and I do not get votes_sum variable.
class Comment(postgres_db.Model, Timestamp):
__tablename__ = 'comment'
id = postgres_db.Column(postgres_db.Integer, primary_key=True)
...
votes_sum = query_expression()
comments_votes_subquery = CommentVote.query. \
join(Comment). \
with_entities(CommentVote.comment_id,
functions.sum(CommentVote.vote).label("votes_sum")). \
group_by(CommentVote.comment_id). \
subquery()
comments_subquery = Comment.query. \
outerjoin(comments_votes_subquery, Comment.id == comments_votes_subquery.c.comment_id). \
options(with_expression(Comment.votes_sum, comments_votes_subquery.c.votes_sum)). \
subquery() # when this ins't a subquery, and I run comments_subquery.populate_existing().all(), I do get Comment.votes_sum data
threads_query = Thread.query. \
outerjoin(comments_subquery, Thread.comments). \
options(contains_eager(Thread.comments))
threads = threads_query.populate_existing().all()

SQL Query to get data from before current time

Im trying to run a query that will allow me to pick out the rows that have the time before current time.
I want to pick out the rows that are before the current time not after. Am i able to order this in a way that can do can do this.
Currently this is my query.
var key = require('../validateApiKey');
// an example of executing a SQL statement directly
module.exports = {"get": [key,function (request, response, next) {
var query = {
sql: 'SELECT dbo.medicine.medname, \
dbo.medicine.packsize,\
dbo.medicine.id as "medicationid",\
dbo.usermedication.isactive, \
dbo.usermedication.reminder, \
dbo.usermedication.communityfeedback, \
dbo.usermedication.frequency, \
dbo.usermedication.directions, \
dbo.usermeddosagetime.usermedid, \
dbo.usermeddosagetime.time,\
dbo.usermedication.datetimetotake, \
dbo.usermeddosagetime.dosage,\
dbo.usermeddosagetime.dosageunit\
FROM dbo.usermedication INNER JOIN dbo.medicine ON dbo.usermedication.medicationid = dbo.medicine.id
INNER JOIN dbo.usermeddosagetime ON dbo.usermedication.id = dbo.usermeddosagetime.usermedid
WHERE dbo.usermedication.userid = #userid AND dbo.usermedication.isactive = 1',
parameters: [
{ name: 'userid', value: request.query.userid }
]
};
request.azureMobile.data.execute(query)
.then(function (results) {
response.json(results);
});
}]
};
Add the following condition to the WHERE clause:
MySQL
AND dbo.usermeddosagetime.time < NOW()
SQL Server
AND dbo.usermeddosagetime.time < GETDATE()

MySQL optional filters for search query

I am working on a query that has an optional filter, so lets assume the table name is products and the filter is the id (primary key)
If the filter is not present I would do something like this:
SELECT * FROM products;
If the filter is present I would need to do something like this:
SELECT * FROM products WHERE id = ?;
I have found some potential solutions that can mix the 2 in sql rather than doing conditions in the back-end code itself
SELECT * FROM products WHERE id = IF(? = '', id, ?);
OR
SELECT * FROM products WHERE IF(? = '',1, id = ?);
I was just wondering which one would be faster (In the case of multiple filters or a very big table) Or is there a better solution to handle this kind of situation?
A better approach is to construct the WHERE clause from the parameters available. This allows the Optimizer to do a much better job.
$wheres = array();
// Add on each filter that the user specified:
if (! empty($col)) { $s = $db->db_res->real_escape_string($col);
$wheres[] = "collection = '$s'"; }
if (! empty($theme)) { $s = $db->db_res->real_escape_string($theme);
$wheres[] = "theme = '$s'"; }
if (! empty($city)) { $s = $db->db_res->real_escape_string($city);
$wheres[] = "city = '$s'"; }
if (! empty($tripday)) { $s = $db->db_res->real_escape_string($tripday);
$wheres[] = "tripday = '$s'"; }
// Prefix with WHERE (unless nothing specified):
$where = empty($wheres) ? '' :
'WHERE ' . implode(' AND ', $wheres);
// Use the WHERE clause in the query:
$sql = "SELECT ...
$where
...";
Simplest approach is OR:
SELECT *
FROM products
WHERE (? IS NULL OR id = ?);
Please note that as you will add more and more conditions with AND, generated plan will be at least poor. There is no fit-them-all solution. If possible you should build your query using conditional logic.
More info: The “Kitchen Sink” Procedure (SQL Server - but idea is the same)

SQL Query with JOIN, WHERE and AND clause to convert in Laravel queries

I'm having problem converting my SQL query to laravel queries. I want to join two tables users and messages so that i can get the users that has conversation with other users.
Database Structure:
Users:
Messages:
This is my SQL query where I get what I want:
SELECT u.id, c.id, u.first_name, u.last_name FROM messages c, users u
WHERE (CASE WHEN c.user_one = #USERID THEN c.user_two = u.ID WHEN c.user_two = #USERID THEN c.user_one= u.id END )
AND ( c.user_one = #USERID OR c.user_two = #USERID ) Order by c.id DESC Limit 20
This is my Laravel query:
DB::table('messages')
->join('users', function($join) use ($user_id) {
$join->select(DB::raw('CASE WHEN messages.user_one = ' . $user_id . ' THEN messages.user_two = ' . $user_id . 'WHEN messages.user_two = ' . $user_id . ' THEN messages.user_one = ' . $user_id));
$join->on(function($query) use ($user_id)
{
$query->where('messages.user_one', '=', $user_id);
$query->orWhere('messages.user_two', '=',$user_id);
});
})
->select('users.*', 'messages.*')
->get();
UPDATE:
Sorry my original answer was not injecting variables in a secure way. Please use this for securely injecting variables in raw queries.
SQL injection security in raw statements.
In raw queries we need remember to pass all variables to our mysql
database using provided second argument.
In your case, you just place question marks placeholders, where you want to have your variables injected and then put your variables in same order as your placeholders in your second argument array.
Source: http://s4.jeffsbio.co.uk/laravel-5-query-builder-where-raw-2
Updated Query:-
DB::table('messages as m')
->join('users as u',function($join){
$join->on('u.id','=','m.user_one')
->orOn('u.id','=','m.user_two');
})
->where(function($query) use($user_id){
$query->where('m.user_one','=',$user_id);
$query->orWhere('m.user_two','=',$user_id);
})
->where(function($query) use($user_id){
$query->whereRaw(
'CASE WHEN m.user_one = ?'.
' THEN m.user_two = u.id'.
' WHEN m.user_two = ?'.
' THEN m.user_one = u.id END',[$user_id,$user_id]);
//here we passed the variables in exact order of their usage in query
})
->select('u.id as user_id', 'm.id as messages_id','u.first_name','u.last_name')
->orderBy('m.id','DESC')
->limit('20')
->get(
Original Answer:
You can't use select clause in join clause like you have.
Use this :-
DB::table('messages as m')
->join('users as u',function($join){
$join->on('u.id','=','m.user_one')
->orOn('u.id','=','m.user_two');
})
->where(function($query) use($user_id){
$query->where('m.user_one','=',$user_id);
$query->orWhere('m.user_two','=',$user_id);
})
->where(function($query) use($user_id){
$query->whereRaw(DB::raw(
'CASE WHEN m.user_one = '.$user_id.
' THEN m.user_two = u.id'.
' WHEN m.user_two = '.$user_id.
' THEN m.user_one = u.id END'));
})
->select('u.id as user_id', 'm.id as messages_id','u.first_name','u.last_name')
->orderBy('m.id','DESC')
->limit('20')
->get();

Left Join from Select Zend Framework

How can I do a Query like this using the Zend framework
SELECT * FROM `productos` AS `p`
LEFT JOIN (SELECT SUM(cantidad) AS transferencias FROM transferencias WHERE upc = p`.`upc` and sucursal = 10)
AS `trans` ON trans.upc = p.upc AND trans.sucursal_clave_destino = 10
Thank you in advance.
You need to try this one.
I can't try it but the way of resolve it you can use from my query
$this->getAdapter()
->select()
->from(array('p' => 'productos'))
->joinLeft(array('trans' => $this->getAdapter()
->select()
->from('transferencias', 'SUM(cantidad)')
->where('upc IN (?)', $this->getAdapter()
->select()
->from('productos', 'upc')
)->where('sucursal = ?', 10)
), 'trans.upc = p.upc')
->where('trans.sucursal_clave_destino = ?', 10)
->query()
->fetchAll();
First of all, I'm afraid it's impossible for your query to run because the syntax is wrong. The correct way to write it is:
SELECT *, SUM(trans.cantidad) as cantidad
FROM productos AS p
LEFT JOIN transferencias AS trans
ON p.upc = trans.upc
WHERE trans.sucursal_clave_destino = 10 AND trans.sucursal = 10
First approach
I assume you have created your model in this manner: http://framework.zend.com/manual/1.12/en/learning.quickstart.create-model.html
For example, in your Default_Model_ProductosMapper:
function getXXXX(){
$select = "[THE ABOVE QUERY]";
$result = $this->getDbTable()->getAdapter()->fetchAll($select);
return $result;
}
This is the most basic approach.
Second approach
By using Zend_Db functions, which is like prepare statement in database concept. Only use it to increase safety if you are passing parameters from user input (see SQL injection), otherwise it's safe to use the first approach.
Still, in your mapper:
function getXXXX(){
$query = $this->getDbTable()->getAdapter()->select();
$query->from('productos', array());
$query->joinLeft('transferencias', 'productos.upc = transferencias.upc', array('SUM(trans.cantidad) as cantidad));
$query->where("trans.sucursal_clave_destino = 10");
$query->where("trans.sucursal = 10");
// get result
$stmt = $this->getDbTable()->getAdapter()->query($query);
$result = $stmt->fetchAll();
return $result;
}
Third approach
If you are using Database ORM like Doctrine2, you can also write SQL or DQL (Doctrine Query Language) queries, which syntax is highly similar with SQL queries but absolutely NOT the same mechanism. The document is here. This document covers both approaches above for DQL and also will tell you where to put them.