Forum Moderators: coopster

Message Too Old, No Replies

Preventing SQL Injection

         

kkonline

9:42 am on Aug 15, 2007 (gmt 0)

10+ Year Member




<?php
$con = mysql_connect("localhost","root","");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("db", $con);

if(!eregi("example.com", $HTTP_REFERER) &&!eregi("www.example.com", $HTTP_REFERER))
{
echo "ERROR: Invalid referer ";
}
else{[b]
$subject = mysql_real_escape_string($subject);
$titletext = mysql_real_escape_string($titletext);
$maintext = mysql_real_escape_string($maintext);
$subject= strip_tags($subject);
$titletext = strip_tags($titletext);
$maintext = strip_tags($maintext);

is this is how you mean to protect the sql injection?
I tested the code i can still get <-----comment-----> and
\x00, \n, \r, \, ', " characters in my db.
WHAT TO DO?
[/b]

$sql="INSERT INTO phpnews_news (time, month, year, subject, titletext, maintext, views, break, catid, trusted)
VALUES
('$_POST[time]','$_POST[month]','$_POST[year]','$_POST[subject]','$_POST[titletext]','$_POST[maintext]','0','0','$_POST[catid]','0')";

if (!mysql_query($sql,$con))
{
die('Error: ' . mysql_error());
}

echo "Article added on ";
echo date('l dS F Y h:i:s A');
echo " from ";
echo $_SERVER['REMOTE_ADDR'];
}
mysql_close($con)

?>

However <?php
echo get_magic_quotes_gpc(); // 1
?> gives a value 1
if that is concerned?

[edited by: kkonline at 10:07 am (utc) on Aug. 15, 2007]

[edited by: dreamcatcher at 2:19 pm (utc) on Aug. 15, 2007]
[edit reason] Exemplified urls. [/edit]

PHP_Chimp

9:56 am on Aug 15, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



On one of my sites I pass all user submitted data through this function -

function clean($i){
if (!get_magic_quotes_gpc()){
$i = addslashes($i);
}
$i = rtrim($i);
$look = array('&', '#', '<', '>', '"', '\'', '(', ')');
$safe = array('&amp;', '&#35', '&lt;', '&gt;', '&quot;', '&#39', '&#40;', '&#41;');
$i = str_replace($look, $safe, $i);
return $i;
}

So it removes all &,#,<,>,",\,( and ) from the user input. You can add or remove whatever characters you want.
The function also trims the input, but you could remove that if you want lots of white space at the end of some inputs.

kkonline

10:18 am on Aug 15, 2007 (gmt 0)

10+ Year Member



so you mean i should do the following:

function clean($subject)

Habtom

10:20 am on Aug 15, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



function clean($subject)

Assuming you want to use the function above do the following:

$subject = clean($subject);

. . . and copy the function where it can be easily included to the page.

Habtom

kkonline

10:46 am on Aug 15, 2007 (gmt 0)

10+ Year Member



I used the following code and posted an html code as maintext and still got the value store in db as below

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>Add/Remove child: Javascript</title>
<script type="text/javascript">
<!--

function insertRowPHP()
{
var tbl = document.getElementById('tblInsertRowPHP');
var iteration = tbl.tBodies[0].rows.length+1;
newRow = tbl.tBodies[0].insertRow(-1);
var newCell = newRow.insertCell(0);
newCell.innerHTML = 'tag ' + iteration;
var newCell1 = newRow.insertCell(1);
var el = document.createElement('input');
el.type = 'text';
el.name = 'tag[]';
el.id = 'tag' + iteration;
el.size = 15;
newCell1.appendChild(el);
}

function deleteRows(tblId)
{
var tbl = document.getElementById(tblId);
var i=tbl.tBodies[0].rows.length-1; {
tbl.tBodies[0].deleteRow(i);
}
}</script>
</head>

<body>

<form action="storyinsert_d.php" method="post">
Titletext: <input type="text" name="titletext" /><br>
Subject: <input type="text" name="subject" /><br>

Maintext: &nbsp;<TEXTAREA NAME="maintext" ROWS="10", COLS="30">Your data</TEXTAREA><br>
Moral: <input type="text" name="moral" /><br>

Category: <select name="catid">
<option value="1">Chocolate Pie</option>
<option value="2">It's Him</option>
<option value="3">Mixed Bag</option>
<option value="4">Director's Cut</option>
</select><br>

<input type="submit" />
1187171399

<input type="hidden" name="year" value="2007" />
<input type="hidden" name="month" value="8" />

<input type="hidden" name="views" value="0" />
<input type="hidden" name="break" value="0" />
<input type="hidden" name="trusted" value="0" />

<input type="hidden" name="time" value="1187171399" />
<input type="hidden" name="ip" value="59.178.98.73" />

14-08-2007 04:22:20

</form>
</body>
</html>

Below is the code i used

<?php
[b]
function clean($i){
if (!get_magic_quotes_gpc()){
$i = addslashes($i);
}
$i = rtrim($i);
$look = array('&', '#', '<', '>', '"', '\'', '(', ')');
$safe = array('&amp;', '&#35', '&lt;', '&gt;', '&quot;', '&#39', '&#40;', '&#41;');
$i = str_replace($look, $safe, $i);
return $i;
}
[/b]
$con = mysql_connect("localhost","root","");
if (!$con)
{
die('Could not connect: ' . mysql_error());
}
mysql_select_db("db", $con);

if(!eregi("example.com", $HTTP_REFERER) &&!eregi("www.example.com", $HTTP_REFERER))
{
echo "ERROR: Invalid referer ";
}
else{
[b]
$subject = clean($subject);
$titletext = clean($titletext);
$maintext = clean($maintext);
[/b]
$sql="INSERT INTO phpnews_news (time, month, year, subject, titletext, maintext, views, break, catid, trusted)
VALUES
('$_POST[time]','$_POST[month]','$_POST[year]','$_POST[subject]','$_POST[titletext]','$_POST[maintext]','0','0','$_POST[catid]','0')";

if (!mysql_query($sql,$con))
{
die('Error: ' . mysql_error());
}

echo "Article added on ";
echo date('l dS F Y h:i:s A');
echo " from ";
echo $_SERVER['REMOTE_ADDR'];
}
mysql_close($con)

?>

now what to do? help please

[edited by: dreamcatcher at 2:19 pm (utc) on Aug. 15, 2007]
[edit reason] Exemplified urls. [/edit]

d40sithui

11:03 am on Aug 15, 2007 (gmt 0)

10+ Year Member



you need to clean the POST vars

$subject = clean($_POST['subject']);
$titletext = clean($_POST['titletext']);
$maintext = clean($_POST['maintext']);

Habtom

11:05 am on Aug 15, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



$subject = clean($_POST[subject]);
$titletext = clean($_POST[titletext]);
$maintext = clean($_POST[maintext]);
$year = clean($_POST[year]);
$month = clean($_POST[month]);
$time = clean($_POST[time]);
$catid = clean($_POST[catid]);
$sql="INSERT INTO phpnews_news (time, month, year, subject, titletext, maintext, views, break, catid, trusted)
VALUES
('$time','$month','$year','$subject','$titletext','$maintext','0','0','$catid','0')";

Btw, if you are inserting the current time, month, and year, you can do it on the query itself or get the current time from the date function of PHP.

<edit> d40sithui, just noticed your post. </edit>

[edited by: Habtom at 11:07 am (utc) on Aug. 15, 2007]

dreamcatcher

2:16 pm on Aug 15, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



An easier way would be to use array_map:

$_POST = array_map [php.net]('clean',$_POST);

Then use the post vars array directly and not assign other vars. But, each to his own.

dc

Habtom

3:39 pm on Aug 15, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



dreamcatcher, that is a very good point. Those little things can save lots of time. thanks for that

dreamcatcher

6:12 pm on Aug 15, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Each to his own Habtom like I say. Thats how I would do it myself. No point in assigning vars unless there is a specific reason too.

dc

kkonline

2:15 pm on Aug 16, 2007 (gmt 0)

10+ Year Member



Another thing is there some kind of code all combined which validates the $_POST strips tags etc. then allows to post to db and also validates $_GET adds the stripped tags and all and then show to the user.. I mean one for all purpose.

what do say abt the following code i found...


function safeEscapeString($string){
if (get_magic_quotes_gpc()) {
return $string;
} else {
return mysql_real_escape_string($string);
}
}
function cleanVar($string){
$string = trim($string);
$string = safeEscapeString($string);
$string = htmlentities($string);
return $string;
}
foreach($_POST as $name => $value){
$_POST[$name] = cleanVar($value);
}
foreach($_GET as $name => $value){
$_GET[$name] = cleanVar($value);
}
foreach($_COOKIE as $name => $value){
$_COOKIE[$name] = cleanVar($value);
}
foreach($_REQUEST as $name => $value){
$_REQUEST[$name] = cleanVar($value);
}

dreamcatcher

3:10 pm on Aug 16, 2007 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member



Well, you can lose the foreach loops in favour of array_map. See my previous post as an example.

dc

kkonline

6:47 am on Aug 17, 2007 (gmt 0)

10+ Year Member



Hi guys,

I have listed some points below[Related to SQL Injection Only]

1> Use of only escape string like mysql_real_escape_string() is necessary and sufficient.

2> You should never use htmlentities or htmlspecialchars as these are encodings for a specific document format. You could not do searching or matching on that data and displaying it in any other document format would take extra code, and could not be done directly from the database.

3> Use of trim() may be used if no spaces in beginning or end are required.

4> You should never need to use stripslashes on output from a database. Aside from security, escaping quotes for instance, is solely for the benefit of the SQL parser. This is no different than escaping quotes in PHP strings, in order to not confuse the PHP parser and get an error. If you echo the string, it will not contain the escape characters, they are there solely to tell the parser what language characters are intended to be part of the string, and which ones are to be interpreted as actual code. The SQL parser in a database is no different.

5> Magic quotes and addslashes are vulnerable to character set differences and should not be used. If you can't turn it off, run code to defeat it, which is the proper use of stripslashes.

There are two codes which i found on the forum please compare them and tell which one is better? Looking at only the input data which is sent to db.

What should be the code/precaution when extracting data from db and displaying them. code for them?

All the above and below things are with respect to sql injection.
Please also discuss the above points and let me know if i have something wrong in above 5 points

Code1
[php]function cleaner($input)
{
if(is_array($input))
{
$ret = array();
foreach($input as $key=>$value)
{
$ret[$key] = cleaner($value);
}
return $ret;
}
else
{
if(!is_numeric($input))
{
if(get_magic_quotes_gpc($input))
{
$input = stripslashes($input);
}
$input = mysql_real_escape_string($input);
}
return $input;
}
}
$dbData = cleaner($_POST);
[/php]

why do we have if(get_magic_quotes_gpc($input))
and not if(get_magic_quotes_gpc())?

Code 2
[php]function safeEscapeString($string){

if (get_magic_quotes_gpc()) {

$string = stripslashes($string);

//defeating magic quote is required!

return $string;

} else {

return mysql_real_escape_string($string);

}

}

function cleanVar($string){

$string = trim($string);

$string = safeEscapeString($string);

$string = strip_tags($string);

// i think strip_tags should be removed

return $string;

}

foreach($_POST as $name => $value){

$_POST[$name] = cleanVar($value);

}

foreach($_GET as $name => $value){

$_GET[$name] = cleanVar($value);

}

foreach($_COOKIE as $name => $value){

$_COOKIE[$name] = cleanVar($value);

}

foreach($_REQUEST as $name => $value){

$_REQUEST[$name] = cleanVar($value);

}[/php]

let me know if the above points i summarized are correct.

I have been on this forum for past 5-6 days and I must say that all your prompt replies with elaborate explanation really helping enthusiasts and increases level of confidence in them. Hats off to you.

Waiting for a reply which covers all my doubts...

If there are some loopholes in the above code then can you tell me the easiest and the most secure code against sql injection.

kkonline

9:08 am on Aug 17, 2007 (gmt 0)

10+ Year Member



An easier way would be to use array_map:

$_POST = array_map('clean',$_POST);

Then use the post vars array directly and not assign other vars. But, each to his own.


function safeEscapeString($string){
if (get_magic_quotes_gpc()) {
return $string;
} else {
return mysql_real_escape_string($string);
}
}
function cleanVar($string){
$string = trim($string);
$string = safeEscapeString($string);
$string = htmlentities($string);
return $string;
}
foreach($_POST as $name => $value){
$_POST[$name] = array_map('cleanVar', $_POST[$name]);
}
foreach($_GET as $name => $value){
$_GET[$name] = array_map('cleanVar', $_GET[$name]);
}
foreach($_COOKIE as $name => $value){
$_COOKIE[$name] = array_map('cleanVar', $_COOKIE[$name]);
}

So dreamcatcher you mean i should write something like above and include in all the php files which require cleaning? Is it correct?

To clean the i should write $string=cleanVar($string); ?