How would someone use sql injection on this query - php

So I have this query in php
SELECT a.sifra,a.slika,a.slika2,a.imeProizvoda,a.opis,b.cijena,b.cijena2
FROM proizvodi a
inner join stanje b
on a.sifra = b.sifra
WHERE a.imeProizvoda LIKE '%$search%'
I tried making sql injection with DROP TABLE proizvodi in every way i found on internet but couldn't make it work
How would someone make that query in search so my database proizvodi is deleted

To avoid SQL injection in PHP, you should absolutely use prepared statements, which make it pretty much impossible to do any SQL injection. For an answer to your question, we can try the following:
$search = "'; DROP TABLE proizvodi; SELECT * FROM dual WHERE '1' LIKE '";
This would result in the following being executed:
SELECT a.sifra, a.slika, a.slika2, a.imeProizvoda, a.opis, b.cijena, b.cijena2
FROM proizvodi a
INNER JOIN stanje b
ON a.sifra = b.sifra
WHERE a.imeProizvoda LIKE '%';
DROP TABLE proizvodi;
SELECT * FROM dual WHERE '1' LIKE '%'
The basic idea is to trip up PHP/MySQL by ending the original valid statement, and then injecting some other (malicious) statement afterwards. Note that DROP and DELETE are not the only damaging things which could happen. For example, doing a SELECT * on a customer table containing credit card numbers could be the most damaging thing to happen.
Disclaimer: I don't live in my parents' basement and spend all my time injecting websites. But, I knew enough to guess at an answer to your question.

Related

PHP MYSQL Query not fetching multiple WHERE Conditions

I have a search feature that onkeydown gives out suggestions. Currently, the query only fetches from one row of the table customer_name, and I'm trying to have the id row as well to be searched for the suggestions.
so my query syntax looks likes this:
$query = "SELECT * FROM customers WHERE customer_name OR id like'%".$search."%' LIMIT 5";
But the above query will only fetches from the second table name i.e., id but not both.
What am I doing wrong here?
I could be wrong, but WHERE customer_name will always evaluate to true and thus include all records. You need to specify what customer_name should be compared to.
Correct query:
SELECT * FROM customers
WHERE customer_name LIKE '%".$search."%'
OR id LIKE '%".$search."%'
LIMIT 5;
As an important security tip, you should look into prepared statements instead of mixing data with your queries. Doing so leaves you vulnerable to SQL injection attacks.

SQL Update across 3 tables - Where clause issue(?)

We need to update various columns on 3 different tables via an input form. most of this is functional however when we try to update the other 2 tables that have been joined (publisher and category), it updates that record and every other record with the same input.
(for example if we change the genre from metal to jazz then all of the metal CD's will change to Jazz as well)
Below is the code we have so far for the update.
$sql = "UPDATE nmc_cd, nmc_category, nmc_publisher
SET CDTitle ='$title', CDYear = '$year', nmc_publisher.pubID = '$publisherID', nmc_category.catID = '$categoryID', CDPrice = '$price', pubName ='$pubName', catDesc='$catDesc'
WHERE CDID = $id
AND nmc_category.catID = nmc_cd.catID
AND nmc_publisher.pubID = nmc_cd.pubID";
I am relatively new to this site so please if anything such as code, names of variables/functions etc. is needed please say and I will edit my post or reply.
Thanks in advance!
A couple of recommendations.
1) qualify all column references in SQL statement that references more than one table, even when the column references aren't ambiguous to MySQL. (Also consider assigning a short alias to each table.) Several reasons for this, but one big one is that it lets a human reader know which table each referenced column is in.
2) ditch the old school comma operator for join operations, and use the JOIN keyword. Also move the join predicates from the WHERE clause to the appropriate ON clause.
3) for a multitable update, first write a SELECT statement, get that working and tested, and then convert that to an UPDATE statement
4) avoid SQL Injection vulnerabilities. The preferred pattern is to use prepared statements with bind placeholders. Or (less optimal) at a minimum, all potentially unsafe values that are included in the SQL text must be properly escaped.
Ignoring SQL Injection vulnerabilities (assuming that the contents of the variables have already been properly escaped)...
I would first write a SELECT statement that returns the current values of the columns we're planning to update, along with the new values we're planning to assign to those columns. For example:
SELECT cd.cdtitle AS old_cd_cdtitle
, '$title' AS new_cd_cdtitle
, cd.cdyear AS old_cdyear
, '$year' AS new_cdyear
, pub.pubid AS old_pub_pubid
, '$publisherID' AS new_pub_pubid
, cat.catid AS old_cat_catid
, '$categoryID' AS new_cat_catid
, cd.cdprice AS old_cd_cdprice
, '$price' AS new_cd_cdprice
, pub.pubName AS old_pub_pubname
, '$pubName' AS new_pub_pubname
, cat.catDesc AS old_cat_catdesc
, '$catDesc' AS new_cat_catdesc
FROM nmc_cd cd
JOIN nmc_category cat
ON cat.catID = cd.catid
JOIN nmc_publisher pub
ON pub.pubID = cd.pubid
WHERE cd.cdid = $id
(That is really just a guess, I'm not sure what you are actually trying to achieve.)
It seems really odd to assign a new value to the catid column, when that's referenced in a join predicate. To maintain the relationship between the rows in cd and cat, the catid in column in both tables would need to be updated, unless we're depending on an ON UPDATE CASCADE rule to propagate the change.
Without understanding what this statement is attempting to achieve, it's not possible to recommend any particular statement.
In terms of converting the SELECT into an UPDATE statement, replace the SELECT ... FROM with the keyword UPDATE.
And before the WHERE clause, add a SET statement. Taking the expresssions for old_cd_cdyear and new_cd_cdyear from the SELECT list, convert that into a SET clause like this:
SET cd.cdyear = '$year'
Subsequent assignments, use a comma in place of the SET keyword, e.g.
, cd.cdprice = '$price'

What does "s." and "n" mean/do in this mysql statement?

I'm currently working on a project that requires me look at someone elses code, i'm still new to some of this stuff and there is something that I dont quite understand so was hoping someone could shed some light on what the code is actually doing or what it means?
Here is the statement in question:
select s.* from $tableA n, $tableB s where
n.id='$send' and
n.status='$status' and
n.field=s.id";
I understand that down to basics this statement is getting all of the fields from tableA and tableB im just unsure what the s. does or what the n does in this statement? are they simply there as identifiers or am I completely wrong in this manner? I am happy to provide more information if it is necessary.
They are called SQL Table Aliases and are basically temporary names which you give to the tables in order to have better readability when you use the table names to specify a column.
In your example
SELECT s.* FROM $tableA n, $tableB s
WHERE n.id='$send'
AND n.status='$status'
AND n.field=s.id ;
is the same as
SELECT $tableB.* FROM $tableA, $tableB
WHERE $tableA.id='$send'
AND $tableA.status = '$status'
AND $tableA.field = $tableB.id ;
but obviously it's easier to read.
The table aliases are even more useful when you join more tables and are absolutely a must when you make self joins.
Syntax note:
You may or you may not use the AS keyword when alias a table.
SELECT table_name AS alias
is the same as
SELECT table_name alias
and although it's longer sometimes it leads to a better readability (for example in a large and messy query the big AS is easier to spot :)

single query for multiple sql queries

I am working on a project where a user can add comments and also hit any post.
Now I have to display the total number of comments and total number of hits and also show whether the user has already hitted that post or not.
So basically I need to do three sql queries for this action:
one counting comments,
one for counting hits and
one for checking whether the user has hitted the post or not.
I wanted to know that if it's possible to reduce these three sql queries into one and reduce the database load?
Any help is appreciated.
$checkifrated=mysql_query("select id from fk_views where (onid='$postid' and hit='hit' and email='$email')");//counting hits
$checkiffollowing=mysql_query("select id from fk_views where (onid='$postid' and hit='hit' and email='$email')");
$hitcheck=mysql_num_rows($checkifrated);//checking if already hited or not
$checkifrated=mysql_query("select id from fk_views where (onid='$postid' and comment !='' and email='$email')");//counting comments
This query returns the number of hits and number of nonempty comments.
select ifnull(sum(hit='hit'),0) as hits, ifnull(sum(comment !=''),0) as comments
from fk_views where onid='$postid' and email='$email'
Based on the queries you provided I dont think you need to query separately if he is hitted the post, just check in you code if number of hits is > 0
Yes, it may be possible to combine the three queries into a single query. That may (or may not) "reduce the database load". The key here is going to be an efficient execution plan, which is going to primarily depend on the availability of suitable indexes.
Combining three inefficient queries into one isn't going to magically make the query more efficient. The key is getting each of the queries to be as efficient as they can be.
If each of the queries is processing rows from the same table, then it may be possible to have a single SELECT statement process the entire set, to obtain the specified result. But if each of the the queries is referencing a different table, then it's likely the most efficient would be to combine them with a UNION ALL set operator.
Absent the schema definition, the queries that you are currently using, and the EXPLAIN output of each query, it's not practical to attempt to provide you with usable advice.
UPDATE
Based on the update to the question, providing sample queries... we note that two of the queries appear to be identical.
It would be much more efficient to have a query return a COUNT() aggregate, than pulling back all of the individual rows to the client and counting them on the client, e.g.
SELECT COUNT(1) AS count_hits
FROM fk_views v
WHERE v.onid = '42'
AND v.hit = 'hit'
AND v.email = 'someone#email.address'
To combine processing of the three queries, we can use conditional expressions in the SELECT list. For example, we could use the equality predicates on the onid and email columms in the WHERE clause, and do the check of the hit column with an expression...
For example:
SELECT SUM(IF(v.hit='hit',1,0)) AS count_hits
, SUM(1) AS count_all
FROM fk_views v
WHERE v.onid = '42'
AND v.email='someone#email.address'
The "trick" to getting three separate queries combined would be to use a common set of equality predicates (the parts of the WHERE clause that match in all three queries).
SELECT SUM(IF(v.hit='hit' ,1,0)) AS count_hits
, SUM(IF(v.comment!='',1,0)) AS count_comments
, SUM(1) AS count_all
FROM fk_views v
WHERE v.onid = '42'
AND v.email ='someone#email.address'
If we are going to insist on using the deprecated mysql interface (over PDO or mysqli) it's important that we use the mysql_real_escape_string function to avoid SQL Injection vulnerabilities
$sql = "SELECT SUM(IF(v.hit='hit' ,1,0)) AS count_hits
, SUM(IF(v.comment!='',1,0)) AS count_comments
, SUM(1) AS count_all
FROM fk_views v
WHERE v.onid = '" . mysql_real_escape_string($postid) . "'
AND v.email = '" . mysql_real_escape_string($email) ;
# for debugging
#echo $sql
$result=mysql_query($sql);
if (!$result) die(mysql_error());
while ($row = mysql_fetch_assoc($result)) {
echo $row['count_hits'];
echo $row['count_comments'];
}
For performance, we'd likely want an index with leading columns of onid and email, e.g.
... ON fk_views (onid,email)
The output from EXPLAIN will show the execution plan.

SQL injection even when the variable is escaped [duplicate]

This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 2 years ago.
The sql injection will work only when my query looks like below sample
SELECT * FROM login WHERE id = $my_id_va;
Assume if my query is
SELECT * FROM login WHERE id = $my_id_va ORDER BY id DESC
Than I will get following error
#1064 - You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'order by id desc' at line 1
So, this 1 or 1=1; SHOW TABLES will not work, correct?
My site was hacked successively many times.
I want one quick answer: When my query looks like the following one, what ways or which types of query can they use to hack my site?
SELECT * FROM login WHERE id = $my_id_va ORDER BY id DESC
What are the ways to execute the show table in the following query
SELECT * FROM login WHERE id = $my_id_va ORDER BY id DESC
I am also using escaping function to handle the query string values, like mysql_real_escape_string($my_id_va). Yes, obviously this for single related hack, but not sure.
Added some more
SELECT EventActuallyCharged, EventDate FROM tblevent WHERE EventDate between '2011-07-21 or 1=1; SHOW TABLES --' and '2011-07-31' ORDER BY EventDate DESC
but show table not worked
If you are using PHP5, use parametarized query, use PDO.
Int cast
If id is a number, you can int-cast your variable as well. Integers are safe to use:
$x = (int)$yourInputVar;
$s = "select * from Table where id = $x";
mysql_real_escape_string
If you want to pass a string, you can, and should, use mysql_real_escape_string, but this function escapes only those characters that are inside the string. You will still need to add quotes around the string, so:
$x = mysql_real_escape_string('hello');
$s = "select * from Table where id = $x";
.. will result in the query: select * from Table where id = hello. This is obiously not a valid query, since hello should be in quotes.
Change the query to:
$x = mysql_real_escape_string('hello');
$s = "select * from Table where id = '$x'";
.. and everything works fine. You add the quotes around, and mysql_real_escape_string takes care of special characters inside the string, if any.
Parameters
Another solution is to use parameterized queries. This can by done using MySQLi or PDO. The advantage is that you only tell your database where a variable should be inserted, and the database takes care of the escaping yourself.
It also may add a performance benefit, because these queries could be cached without their parameters, make a more efficient use of the query cache. This doesn't really work yet in current versions of MySQL, though.
You are right that 1 or 1=1; SHOW TABLES will give a syntax error but this will work:
1 or 1=1 --
The -- comments out the rest of the query.
In your case the value is an integer so instead of using mysql_real_escape_string you can use intval.
If you set $my_id_va to:
1 or 1=1; SHOW TABLES --
The -- will comment out the rest of the command, effectively terminating it.
I'm not sure what effect mysql_real_escape_string will have on the query. What you should be doing is parameterized queries.
1. First query somehow secured
$sql = sprintf('SELECT * FROM login WHERE id = %d ORDER BY id DESC', mysql_real_escape_string($my_id_va));
2. Second query somehow secured
$sql = sprintf("SELECT EventActuallyCharged, EventDate FROM tblevent WHERE EventDate BETWEEN '%s' AND '%s' ORDER BY EventDate DESC",
mysql_real_escape_string($start_date),
mysql_real_escape_string($end_date));
Read the docs about sprintf if you don't understand it.
However, as others have said, it would be very very secure if you would use parameterized queries with a class such as PDO or MySQLi.

Categories