3

I have been using the block of code below to supposedly stop sql injections. It is something someone showed me when I first started php(which was not that long ago)

I place it in every page just as shown on the open. I am wondering if it is effective? I do not know how to test for sql injections

<?php

//Start the session

session_start();


//=======================open connection

include ('lib/dbconfig.php');

//===============This stops SQL Injection in POST vars

  foreach ($_POST as $key => $value) {
    $_POST[$key] = mysql_real_escape_string($value);
  }

  foreach ($_GET as $key => $value) {
    $_GET[$key] = mysql_real_escape_string($value);
  }

My typical insert and update queries look like this

$insert = ("'$email','$pw','$company', '$co_description', '$categroy', '$url', '$street', '$suite', '$city', '$state', '$zip', '$phone', '$date', '$actkey'");

mysql_query("INSERT INTO provider (email, pw, company, co_description, category, url, street, suite, city, state, zip, phone, regdate, actkey) VALUES ($insert)") or die ('error ' . mysql_error());

mysql_query("UPDATE coupon SET head='$_POST[head]', fineprint='$_POST[fineprint]', exdate='$exdate', creationdate=NOW() WHERE id='$cid'") or die ('error ' . mysql_error());
Daniel Hunter
  • 2,546
  • 6
  • 28
  • 34
  • It seems your code will be OK, but the approach is so wrong. The world advanced since the marry days of early PHP. Use PDO/MySQLI. Use parameterized queries, use a single access point into your DB... – Itay Moav -Malimovka Nov 12 '11 at 15:54
  • Thanks for answering, excuse the ignorance but can you elaborate on single access point. IN my current projects, I access the database on each page making entries and queries. This is incorrect? – Daniel Hunter Nov 12 '11 at 16:02
  • 1
    I usually have one class to manage connections to the DB and low level operations (like running the queries against the DB and getting back the result). I have another layer on top of that which is responsible on getting requests in different formats and translating it into SQL, that layer is also the only one that cleans the data, and I always use that class to create sql. That way I am pretty sure I am safe from SQL injection, and if I am not, I need to fix this in one place only. – Itay Moav -Malimovka Nov 12 '11 at 16:09

5 Answers5

4

That's somewhat effective, but it's suboptimal -- not all of the data you receive in _GET and _POST will go into the database. Sometimes you might want to display it on the page instead, in which case mysql_real_escape_string can only hurt (instead, you'd want htmlentities).

My rule of thumb is to only escape something immediately before putting it into the context in which it needs to be escaped.

In this context, you'd be better of just using parameterized queries -- then escaping is done for you automatically.

Frank Farmer
  • 38,246
  • 12
  • 71
  • 89
3

This is not enough. 1. You're missing cookies, $_COOKIE variable. 2. If you use $_REQUEST you're in trouble. 3. You didn't show your queries, you must enquote each variable with single quotes '' when you put it into query (especiall when the data is supposted to be an integer and you might think that quote is not necessary in that case, but that would be a big mistake). 4. Data used in your query could come from other source.

The best way is to use data binding and have the data escaped automatically by the driver, this is available in PDO extension.

Example code:

$PDO = new PDO('mysql:dbname=testdb;host=127.0.0.1' $user, $password);
$stmt = $PDO->prepare("SELECT * FROM test WHERE id=? AND cat=?");
$stmt->execute(array($_GET["id"], $_GET["cat"]));
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

You can also bind data using string keys:

$stmt = $PDO->prepare("SELECT * FROM test WHERE id = :id AND cat = :cat");
$stmt->execute(array(":id" => $_GET["id"], ":cat" => $_GET["cat"]));

If you want to learn PDO, you might find useful these helper functions I use:

http://www.gosu.pl/var/PDO.txt

PDO_Connect(dsn, user, passwd) - connects and sets error handling.
PDO_Execute(query [, params]) - only execute query, do not fetch any data.
PDO_InsertId() - last insert id.

PDO_FetchOne(query [, params]) - fetch 1 value, $count = PDO_FetchOne("SELECT COUNT(*) ..");
PDO_FetchRow(query [, params]) - fetch 1 row.
PDO_FetchAll(query [, params]) - fetch all rows.
PDO_FetchAssoc(query [, params]) - returns an associative array, when you need 1 or 2 cols

1) $names = PDO_FetchAssoc("SELECT name FROM table");
the returned array is: array(name, name, ...)

2) $assoc = PDO_FetchAssoc("SELECT id, name FROM table")
the returned array is: array(id=> name, id=>name, ...)

3) $assoc = PDO_FetchAssoc("SELECT id, name, other FROM table");
the returned array is: array(id=> array(id=>'',name=>'',other=>''), id=>array(..), ..)

Each of functions that fetch data accept as 2nd argument parameters array (which is optional), used for automatic data binding against sql injections. Use of it has been presented earlier in this post.

Czarek Tomczak
  • 20,079
  • 5
  • 49
  • 56
  • Can't say whether these queries are safe, because the whole "$inserts=" line is not using $_GET/$_POST variables. The same goes for the 3rd line, using '$cid'. – Czarek Tomczak Nov 12 '11 at 16:29
  • right.. All Login's and inserts are done with post. Orly some of my queries that pull data to be displayed are done with GET but i try to avoid that. Thanks for taking the time.. – Daniel Hunter Nov 12 '11 at 16:38
  • Looks like my next field of study is PDO... first time to read about it – Daniel Hunter Nov 12 '11 at 16:40
  • I've edited my answer and added a link to a few PDO functions I've written myself that make using PDO even easier. – Czarek Tomczak Nov 12 '11 at 17:10
  • Using PDO you can connect to any database you like, so when you've learnt it, you will be able to use the same functions for all databases: mysql, postgresql, sqlite - you only change in the dsn from "mysql" to "sqlite". – Czarek Tomczak Nov 12 '11 at 17:27
2

Kind of.

The mysql_real_escape_string function takes the given variable and escapes it for SQL queries. So you can safely append the string into a query like

$safe =  mysql_real_escape_string($unsafe_string);
$query = 'SELECT * FROM MyTable WHERE Name LIKE "' . $safe . '" LIMIT 1';

It does NOT protect you against someone putting malicious code into that query to be displayed later (i.e. XSS or similar attack). So if someone sets a variable to be

// $unsafe_string = '<script src="http://dangerous.org/script.js"></script>'
$safe =  mysql_real_escape_string($unsafe_string);
$query = 'UPDATE MyTable SET Name = "' . $safe . '"';

That query will execute as you expect, but now on any page where you print this guy's name, his script will execute.

Robert Martin
  • 16,759
  • 15
  • 61
  • 87
  • Thanks. This is something I have not thought about, inserting an entire script link... A lot to study now. Thank you for answering. – Daniel Hunter Nov 12 '11 at 16:39
  • @Daniel this is completely wrong statement. mysql_real_escape_string doesn't make anything "safe". – Your Common Sense Nov 15 '11 at 15:10
  • @Col.Shrapnel I think what you're trying to say is, "just because a string is safe for inserting into a MySQL query doesn't mean it's safe." Which is exactly what I tried to communicate in this post. To claim what I've written is completely wrong is rhetorical and misleading. To quote, `mysql_real_escape_string` "[Escapes special characters in a string for use in an SQL statement](http://php.net/manual/en/function.mysql-real-escape-string.php)". – Robert Martin Nov 15 '11 at 17:03
  • Nope. I am trying to say that mysql_real_escape_string doesn't make "given variable" "safe for inserting into a MySQL query". Strictly speaking, it has nothing to do with "safety". Although your latter statement is more correct, the statement in your answer is totally misleading and will lead to injection. – Your Common Sense Nov 15 '11 at 17:12
  • @Col.Shrapnel reworded for clarification. Hopefully nobody will be misled. Though based on Daniel's reply, I think he understood my meaning. – Robert Martin Nov 15 '11 at 17:54
  • dunno what you reworded but **mysql_real_escape_string doesn't make anything "safe".** assuming that will lead you to injection. – Your Common Sense Nov 15 '11 at 19:18
1

This is completely WRONG approach.

In fact, you are mimicking infamous magic quotes, which is acknowledged as a bad practice. With all it's faults and dangers.

Community
  • 1
  • 1
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
  • Ok, well can you point me in the right direction? maybe a tutorial. I am beginning to build extensive data management systems and do not want to start with bad practices. Thanks for responding. – Daniel Hunter Nov 15 '11 at 16:55
  • 1
    altough prepared statements is good solution, if you want better understanding here are some links for you – Your Common Sense Nov 15 '11 at 19:47
-2

this is not to prevent SQL Injection the real escape method only add \ to the dangerous

characters like " or ' so a string with "hi"do'like" will become "hi\"do\'like\" so it is

less dangerous

this method is not always usefull ; in case you want to display the content of tha escaped

variable in a page it will only destroy it and make it less readable

Qchmqs
  • 1,803
  • 2
  • 20
  • 29