0

I am not experienced with mysql or php and i keep mentioning that in my questions but people keep saying you need mysql injection protection and I've looked it up and i really don't get it. Can anyone help me? I am so new to mysql and am having a bit of trouble with it

Here is my code:

How can it be improved? When i go to view my source code by right clicking on the site, none of the php/mysql appears.

<?php
$conn = mysql_connect("", "", "");
if (!$conn) {
  echo "Unable to connect to DB: " . mysql_error();
  exit;
}

$search = "%".$_POST["search"]."%";
$searchterm = "%".$_POST["searchterm"]."%";

if (!mysql_select_db("")) {
  echo "Unable to select mydbname: " . mysql_error();
  exit;
}

$sql = "SELECT name,lastname,email 
        FROM test_mysql
        WHERE name LIKE '%".$search."%' AND lastname LIKE '%".$searchterm."%'";
$result = mysql_query($sql);

if (!$result) {
  echo "Could not successfully run query ($sql) from DB: " . mysql_error();
  exit;
}

if(empty($_GET['search'])){ // or whatever your field's name is
  echo 'no results';
} else {
  performSearch(); // do what you're doing right now
}

if (mysql_num_rows($result) == 0) {
  echo "No rows found, nothing to print so am exiting";
  exit;
}
while ($row = mysql_fetch_assoc($result)) {
  echo '<br><br><div class="data1">';
  echo $row["name"];
  echo '</div><br><div class="data2">';
  echo $row["lastname"];
  echo '</div><br><div class="data3">';
  echo $row["email"];
  echo '</div>';
}
mysql_free_result($result);

?>
phihag
  • 278,196
  • 72
  • 453
  • 469
James
  • 1,895
  • 6
  • 27
  • 34

6 Answers6

15

SQL injection is best summarised by this comic:

Did you really name your son Robert'); DROP TABLE Students;-- ?"

bobby-tables.com explains how to defend against it in various languages.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
5

SQL injection is the name of the attack, but the underlying problem is insufficient input verification. Take the following code:

$search = $_POST['search'];
$sql = "SELECT name,lastname,email
FROM   test_mysql
WHERE  name LIKE '%".$search."%'";
$result = mysql_query($sql);

What happens if someone enters O'Reilly in the search form?

Well, the query is eventually constructed as:

SELECT name, lastname, email FROM test_mysql
WHERE name LIKE '%O'Reilly%'

This is not a valid SQL query, but will merely lead to an error message. Therefore, your code is buggy; it cannot handle inputs that contain '.

Now, let's consider a malicious person, Mallory. Causing the error doesn't help Mallory in his evil ways, unless he wants to stress database administrators who read all the error logs. He inputs: %'; INSERT INTO test_mysql name,lastname,email VALUES('mal','ory','malory@evil.com');--. Now, the complete SQL query is

SELECT name, lastname, email FROM test_mysql
       WHERE name LIKE '%%';
INSERT INTO test_mysql name,lastname,email
       VALUES('mal','ory','malory@evil.com');
--%'

The last line is a comment and ignored. Mallory can now write arbitrary things to the database!

Note that this requires the ability to execute more than one command in one MySQL. If that feature is not enabled, Mallory has to resort to using subqueries and predicates. In some cases, Mallory should not be able to view the whole table (for example, he should only be able to view his purchases in a webshop, not other customers'). He can simply input ' OR ''=' to see the whole content of the query.

You can protect yourself by either escaping values, like this:

$search = $_POST['search'];
$sql = "SELECT name,lastname,email
FROM   test_mysql
WHERE  name LIKE '%". mysql_real_escape_string($search) ."%'";
$result = mysql_query($sql);

Alternatively, use PDO and prepared statements:

$sql = "SELECT name,lastname,email
FROM   test_mysql
WHERE  name LIKE :search";
$statement = $pdo->execute($sql,
               array(':search' => '%' . $_POST['search'] . '%'));
phihag
  • 278,196
  • 72
  • 453
  • 469
  • But how do you know how protected you need to be? is there just a line/couple of lines of code i can use to stop people harming my database? – James Oct 25 '11 at 17:46
  • @James Extended. The easiest way is to call [`mysql_real_escape_string`](http://php.net/mysql_real_escape_string) on every value. In the long term, you should really switch to PDO. Why are you still using the age-old `mysql_` functions? – phihag Oct 25 '11 at 17:50
  • But now my search doesn't work they way i wanted it to? does your solution match up to the SELECT part of my code? – James Oct 25 '11 at 17:59
  • @James I took the liberty of simplifying the code by removing `AND lastname LIKE '%".$searchterm."%'`. Feel free to ask a question *with less than 20 lines* of php code demonstrating the problem you now encouter. – phihag Oct 25 '11 at 18:11
  • Fatal error: Call to a member function execute() on a non-object in /websites/123reg/LinuxPackage22/we/ez/y_/weezy.co.uk/public_html/newresults.php on line 96 which is the PDO line beginning with statement Thanks so far for the help! – James Oct 25 '11 at 18:41
  • @James If you decide to switch to PDO, you'll need to modify more than this one line. Every database-related line will need to be changed. Therefore, as a hot fix, use `mysql_real_escape_string`. – phihag Oct 25 '11 at 18:42
  • I have now used that code but it has affected the results that are shown. I had it so results only showed that matched 'search' and 'search term' but now results show from matching 'search' – James Oct 25 '11 at 18:50
  • http://www.weezy.co.uk/newresults.php type in 'Trainee' in the first box and 'Kent' in the second. As you can see both the trainee job from kent and the trainee job from essex appear. How can I have it so only the KENT job shows – James Oct 25 '11 at 18:53
  • @James Oh, sorry, didn't see you used double percent sign around variables. Why do you have that? Set `$searchterm` to the real search term without percent signs, as in `$searchterm = $_POST['searchterm'];`. – phihag Oct 25 '11 at 19:11
  • I updated my php code above! Please check it. I edited it but it still doesn't work by matching the two fields. What am i doing wrong? Is it protected now that i added your part in too? – James Oct 25 '11 at 19:14
  • @James **Please do not update the question with a partial solution.** Doing so prevents future searchers from understanding the problem. **Instead, ask a new question**. There is no limit on questions and they're free. – phihag Oct 25 '11 at 19:24
  • Sorry! I tried starting a new question but it won't let me it has a limit of 6 a day. How can i get my code back to working so the two search fields match like i mentioned above? – James Oct 25 '11 at 19:27
  • @James As I said 4 comments ago: I didn't see you used double percent sign around variables. Why do you have that? Set `$searchterm` to the real search term without percent signs, as in `$searchterm = $_POST['searchterm'];`. – phihag Oct 25 '11 at 19:37
  • How do I make it so each search field's entry matches so name and last name match in the database and only them rows are shown? I have included what you said but how do I get it so it does what I just mentioned? – James Oct 25 '11 at 21:46
  • @James Sorry, I don't know what else to tell you - you keep repeating the same unspecific problem description. Can you at least give me the SQL string generated *after* applying `mysql_real_escape_char` or a [link](http://pastebin.com) to the new version? – phihag Oct 25 '11 at 21:52
  • http://www.weezy.co.uk/newresults.php for instance 1) search 'trainee' in the first search box at the top. 2) notice how two sets of results show, one has 'kent' and the other says 'essex'. 3) search 'trainee' in the same box with 'kent' in the second 4) notice how the essex result is still showing. How do I make it so results only show that match the two fields. 'trainee' corresponds to the '$name' and 'kent' corresponds to the '$lastname' part. So what I want is if i search trainee and kent only the trainee and kent results show not the essex ones too like it does at the moment. Hope helps! – James Oct 25 '11 at 21:59
  • @James Sorry, I don't know what else to tell you - you keep repeating the same unspecific problem description. The link to your *website* doesn't help at all - I need to see the *code* (or the mentioned debugging output of the SQL statement), not the rendered page. – phihag Oct 25 '11 at 22:22
  • http://stackoverflow.com/questions/7896629/i-want-my-search-to-only-show-results-with-matching-field-values-how-is-this-do Check out this question I just posted, it might make it a bit clearer! Thanks for keeping up with the help so far! – James Oct 25 '11 at 22:26
1

You need to escape your queries with mysql_real_escape string:

WHERE  name LIKE '%".mysql_real_escape_string($search)."%' AND lastname LIKE '%".mysql_real_escape_string($searchterm)."%'";

You can see examples for SQL injection here: http://www.tizag.com/mysqlTutorial/mysql-php-sql-injection.php

Jordy
  • 4,719
  • 11
  • 47
  • 81
  • thanks, i included that line but got this: Parse error: syntax error, unexpected T_STRING in /websites/123reg/LinuxPackage22/we/ez/y_/weezy.co.uk/public_html/newresults.php on line 92 – James Oct 25 '11 at 17:40
  • Your variable already contains the %-tokens. You don't need it there. The % in the SQl is ok. – Jordy Oct 25 '11 at 17:42
  • Sorry i don't understand, i have to get rid of something? – James Oct 25 '11 at 17:44
  • Change this: $search = "%".$_POST["search"]."%"; to this: $search = $_POST["search"];. Do the same for $searchterm. – Jordy Oct 26 '11 at 08:18
1

Note that not only do you have an SQL-injection in your example code, but you also have an XSS security hole in there:

Code horror

while ($row = mysql_fetch_assoc($result)) {
  echo '<br><br><div class="data1">';
  echo $row["name"];
  echo '</div><br><div class="data2">';
  echo $row["lastname"];
  echo '</div><br><div class="data3">';
  echo $row["email"];
  echo '</div>';
}

You are echoing unsanitized output into a HTML page.
If a user has inputted html code in the name, lastname and/or email fields.
They can inject arbitrary html into your page.
This is called cross server site scripting or XSS.

You need to always sanitize the output that you echo like so:

Safe code

while ($row = mysql_fetch_assoc($result)) {
  echo '<br><br><div class="data1">';
  echo htmlentities($row["name"]);       <<-- sanitize your output!
  echo '</div><br><div class="data2">';
  echo htmlentities($row["lastname"]);
  echo '</div><br><div class="data3">';
  echo htmlentities($row["email"]);
  echo '</div>';
}

See: What are the best practices for avoiding xss attacks in a PHP site

Community
  • 1
  • 1
Johan
  • 74,508
  • 24
  • 191
  • 319
  • when i right click my website and view source code none of my mysql and php is shown. do i still need to haf – James Oct 25 '11 at 19:19
  • YES, you do. An attacker does not need to see your code to hack the site. SQL is a standard and has a very limited syntax and HTML injection works pretty much regardless of the HTML around it, so the protection is very much needed. (BTW XSS is the #1 threat and SQL injection the #2 thread to websites according to SANS) and have been for many many years. – Johan Oct 25 '11 at 19:28
0

You should specifically look at this line:

$sql = "SELECT name,lastname,email 
FROM   test_mysql
WHERE  name LIKE '%".$search."%' AND lastname LIKE '%".$searchterm."%'";

What are possible values that users could send in their post request to make this do something you do not want (like DROP the table!!)

This is what SQL injection is, and if not protected against, it can be very harmful.

nicholas.hauschild
  • 42,483
  • 9
  • 127
  • 120
  • thats the thing i am very new to mysql so i do not understand. How can they do this if they can't see the code? – James Oct 25 '11 at 17:42
  • @James, you try and try until you succeed. There are automated tools that will try all reasonable options. – Johan Oct 25 '11 at 17:46
  • so how am i meant to write the above code to stop people doing this? – James Oct 25 '11 at 17:48
  • James, How did you come up with your table structure? A clever 'hacker' can take a look at your code and probably make reasonable inferences about the structure of your database. And as @Johan said, automated tools will be able to make their various attempts go much faster. – nicholas.hauschild Oct 25 '11 at 17:48
  • You must limit DROP and other privileges for the web user and leave only necessary onces! – Ilia Ross Aug 13 '12 at 20:14
0

SQL Injection is where the enduser is able to inject SQL code into your queries and mess with your databases.

For example, if you were running: UPDATE users SET userID=" + userID + " WHERE id = " + id + ";;

The user could put "; DROP TABLE users; as their input for the userID and SQL will run that query exactly. It can't detect a "bad" query.

You can protect yourself by using paramaterized queries, which there is multiple ways to do in PHP and you can just google "sql parameters php".

Johan
  • 74,508
  • 24
  • 191
  • 319
Madeline
  • 645
  • 1
  • 9
  • 19
  • 1
    This is a widespread misunderstanding, the `;`+new query thick does not work in php, because the `mysql_` lib does not allow 2 queries in one statement. A `' or (1=1) union all select username, password from users -- ` does work however. – Johan Oct 25 '11 at 17:59