Problems with space within parameters of a php function - php

Sorry for not formatting my code. the toolbar was gone...
I want to insert some data into a mysql db. I've wrote a function in php:
function add_ID($ID, $token) {
$add = "INSERT INTO ids (ID, token) VALUES ('$ID', '$token')";
mysql_query($add);
echo 'added successfully';
}
if(isset($_GET['addDeviceID'])) {
add_ID($_GET['ID'], $_GET['token']);
}
In the URL-Field of my Browswe I'am calling the function like that:
http://www.justanexample.com/example.php?ID=123123123&token=qwertzuiop
That works.
If I put a space into either one of the parameters for example like that:
http://www.justanexample.com/example.php?ID=123123 123&token=qwertzuiop
Nothing was added to my mysql db.
Would be great to get some help :)
Thank you!

You should validate your input before sending it to the database. Or, if validation is not possible, filter and/or escape the value.
Validation
If you expect ID to be a integer greater than zero:
if (!ctype_digit($ID)) {
// invalid ID
}
If you expect token to be an alphanumeric string:
if (!ctype_alnum($token)) {
// invalid token
}
Filtering
Filtering is removing invalid parts of the input so that it becomes valid:
if (!ctype_digit($ID)) {
$ID = preg_replace('/\D+/', '', $ID);
// $ID does now only contain digits
}
if (!ctype_alnum($token)) {
$token = preg_replace('/\D+/', '', $token);
// $token does now only contain alphanumeric characters
}
Escaping
Escaping is replacing the meta characters of a specific context some string is meant to be placed in. For MySQL queries you should use a function that escapes the meta characters of the context string declaration in MySQL. PHP has the mysql_real_escape_string function for that purpose:
$add = "INSERT INTO ids (ID, token) VALUES ('".mysql_real_escape_string($ID)."', '".mysql_real_escape_string($token)."')";

Your function is vulnerable to SQL injection. You should validate all user-received parameters before using them in an SQL query, and pass any strings through mysql_real_escape_string, because then I could just pass in something like example.php?token='; DROP DATABASE; and royally screw up your application.
In your case, you should make a check that the received parameters are in the form that you expect first, return an error to the user if they don't, and only then pass them into the SQL query.
function add_ID($ID, $token) {
$id = mysql_real_escape_string($id);
$token = mysql_real_escape_string($token);
$add = "INSERT INTO ids (ID, token) VALUES ('$ID', '$token')";
mysql_query($add);
echo 'added successfully';
}
if(isset($_GET['addDeviceID'])) {
$id = isset($_GET['id']) ? $_GET['id'] : 0; // in case no ID has been passed in
$token = isset($_GET['token']) ? $_GET['token'] : '';
if (!is_numeric($id) {
die('ID is not a number');
}
// validate token here as well
add_ID($id, $token);
}
You should also look into parametrized queries, which are an overall much better way of doing SQL queries with parameters than just using string concatenation. For that, look into using the mysqli extension instead of mysql, or at a higher level, PDO.

Remove space from them using str_replace function eg:
$ID = str_replace(' ', '', $ID);
$token= str_replace(' ', '', $token);
$add = "INSERT INTO ids (ID, token) VALUES ('$ID', '$token')";
Also, I suspect your $ID is a integer field in your table so you can run your query without specifying quotes eg:
$add = "INSERT INTO ids (ID, token) VALUES ($ID, '$token')";

Your code is assuming the query successfully completes without ever checking if there was an error. I'm guessing it'll be a syntax error due to the spaces. If your ID field is an integer type, then doing ID=123 123 will be the syntax error. Including all the SQL injection and data sanitizing advice in the other answers, you should rewrite your add_ID function as follows:
function add_ID($ID, $token) {
$query = 'blah blah blah';
mysql_query($query);
if (mysql_error()) {
echo 'ruhroh, someone set us up the bomb: ', mysql_error();
} else {
echo 'woohoo, it worked!';
}
}
At least this will tell you if the query REALLY did succeed, and what blew up if it didn't. Never assume that a database query of any sort will succeed. There's far too many ways for it to blow up (server died, transaction deadlock, connection pool exhausted, out of disk space, etc...) to NOT have even some simplistic error handling as above.

You can use str_replace to remove spaces. But it's not a good practice.
How can URL's be modified so? In normal cases it's unreal.
Contrary, you should test all input values from user(ID must be an integer, Token shouldn't contains "'" symbol and other checks). Read about sql-injections.

Related

Lot's of blank spaces getting into database.... (PHP, Mysql)

Good day,
First off I'm an I.T starting to get into coding, so please be gentle ^^.
So currently I'm building a script where it takes input (Nexmo) and sends it to my database.
Sadly LOTS of blank spaces seem to be filling up my database. For some reason I can't seem to be able to filter out these nulls?
Would anyone be willing to help?
Thanks!
Heres the code
require('db.php');
if (!$connect) {
die('Could not connect: ' .mysql_error());
}
$sql = "INSERT INTO `INCOMING` (`TO`, `TEXT` , `FROM`, `MESSAGEID`) VALUES ('$_GET[to]','$_GET[text]' ,'$_GET[msisdn]' , '$_GET[messageId]')";
if (!mysql_query($sql)){
die('Error: ' . mysql_error());
}
else {
echo "TO";
}
mysql_close();
Welcome to StackOverflow and to programming!
First of all, I get that you're learning but I'm going to be hard on you to help you. You've got a bad habit from a book or tutorial and I'm not going to let you learn it.
SQL Injection is the #1 vulnerability on OWASP. By inserting data directly from the request (i.e., $_GET) into a SQL query, you are exposing this vulnerability. At the very minimum, escape the data first before integrating with the query
$to = mysql_real_escape_string($_GET['to']);
$text = mysql_real_escape_string($_GET['text']);
$msisdn = mysql_real_escape_string($_GET['msisdn']);
$messageId = mysql_real_escape_string($_GET['messageId']);
$sql = "INSERT INTO `INCOMING` (`TO`, `TEXT` , `FROM`, `MESSAGEID`) VALUES ('$to','$text' ,'$msisdn' , '$messageId')";
I know it looks like more work but good programming is not about saving yourself keystrokes. That being said, you're much better off switching to PDO and using parameterized queries. Besides, the mysql_* family of functions are deprecated.
Now - on to your actual problem. All incoming data needs to be validated and oftentimes filtered to match the business rules of your application. For example, if you want to require that all of these fields have at least one non-whitespace character, you'll need to enforce that. Building off the snippet from above:
function filterInput($value)
{
// Trim all leading/trailing whitespace and newlines
return preg_replace('/^[\s\r\n]+|[\s\r\n]+$/', $value);
}
function validateInput($value)
{
if (NULL === $value || '' === $value) {
return false;
}
return true;
}
// Filter input per your business rules
$to = filterInput($_GET['to']);
$text = filterInput($_GET['text']);
$msisdn = filterInput($_GET['msisdn']);
$messageId = filterInput($_GET['messageId']);
// Now verify they all have real values
if (validateInput($to) && validateInput($text) && validateInput($msisdn) && validateInput($messageId)) {
// Now escape for SQL
$to = mysql_real_escape_string($to);
$text = mysql_real_escape_string($text);
$msisdn = mysql_real_escape_string($msisdn);
$messageId = mysql_real_escape_string($messageId);
// Proceed with INSERT
}
And yet again, I'm sure you're thinking "holy cow that looks like a lot of work" because I took one line of your code and turned it into 20, but that's part of the deal with programming. It's also why people spend lots and lots of time writing libraries and frameworks to abstract-away a lot of this type of "grunt work" code.
Happy coding!
To make sure you don't send empty spaces to the database, you could replace
$sql = "INSERT INTO `INCOMING` (`TO`, `TEXT` , `FROM`, `MESSAGEID`)
VALUES ('$_GET[to]','$_GET[text]' ,'$_GET[msisdn]' , '$_GET[messageId]')";
with
if( !empty($_GET['to']) and !empty($_GET['text']) and !empty($_GET['msisdn']) and !empty($_GET['messageId']) ) {
$sql = sprintf("INSERT INTO `INCOMING` (`TO`, `TEXT` , `FROM`, `MESSAGEID`)
VALUES ('%s','%s' ,'%s' , '%s')",
trim($_GET['to']), trim($_GET['text']),
trim($_GET['msisdn']), trim($_GET['messageId']));
}
This way you'll have leading and trailing spaces, new-lines and other not-printable characters removed before the insert and the insert will only be executed if you have all the information.
Aside from that, the only thing to make sure is that your columns are not of type CHAR, as that would cause the empty spaces regarding of what you send from your code.
I'd also advise against sending information from the browser (GET) straight to the database as it could cause some serious security issues.

Seemingly identical sql queries in php, but one inserts an extra row

I generate the below query in two ways, but use the same function to insert into the database:
INSERT INTO person VALUES('','john', 'smith','new york', 'NY', '123456');
The below method results in CORRECT inserts, with no extra blank row in the sql database
foreach($_POST as $item)
$statement .= "'$item', ";
$size = count($statement);
$statement = substr($statement, 0, $size-3);
$statement .= ");";
The code below should be generating an identical query to the one above (they echo identically), but when I use it, an extra blank row (with an id) is inserted into the database, after the correct row with data. so two rows are inserted each time.
$mytest = "INSERT INTO person VALUES('','$_POST[name]', '$_POST[address]','$_POST[city]', '$_POST[state]', '$_POST[zip]');";
Because I need to run validations on posted items from the form, and need to do some manipulations before storing it into the database, I need to be able to use the second query method.
I can't understand how the two could be different. I'm using the exact same functions to connect and insert into the database, so the problem can't be there.
below is my insert function for reference:
function do_insertion($query) {
$db = get_db_connection();
if(!($result = mysqli_query($db, $query))) {
#die('SQL ERROR: '. mysqli_error($db));
write_error_page(mysqli_error($db));
} #end if
}
Thank you for any insite/help on this.
Using your $_POST directly in your query is opening you up to a lot of bad things, it's just bad practice. You should at least do something to clean your data before going to your database.
The $_POST variable often times can contain additional values depending on the browser, form submit. Have you tried doing a null/empty check in your foreach?
!~ Pseudo Code DO NOT USE IN PRODUCTION ~!
foreach($_POST as $item)
{
if(isset($item) && $item != "")
{
$statement .= "'$item', ";
$size = count($statement);
$statement = substr($statement, 0, $size-3);
$statement .= ");";
}
}
Please read #tadman's comment about using bind_param and protecting yourself against SQL injection. For the sake of answering your question it's likely your $_POST contains empty data that is being put into your query and resulting in the added row.
as #yycdev stated, you are in risk of SQL injection. Start by reading this and rewrite your code by proper use of protecting your database. SQL injection is not fun and will produce many bugs.

Making multiple replacements using str_replace in php

OK here's the problem:
I'm trying to write the query function for a database class in my project and I want to make it easier to escape the sql and check if it is harmful to the database in anyway.
Let's say I have a query like this:
INSERT INTO users (id,name,email,username,birthdate)
VALUES(1,'Josh','josh101#coolsite.com','josh101','1978-11-02')
But it won't really help If I hardcode this into the function. So lets say I used a question mark for all the values I want to insert and then pass an array to the function containing the actual values I want to replace, just like the way it's done in codeigniter.
Here's a sample:
//Here's the way the function appears in the class definition.
public function query($sql,$params=array()){
if (!empty($params) && is_string($sql)):
//do some stuff here.
elseif (empty($params) && is_string($sql)):
//do some other stuff here.
else:
//bad sql argument.
die("Mysql_database ERROR: The query submitted is not a string!");
endif;
}
//Here's where the function is applied.
$sql="INSERT INTO users (id,name,email,username,birthdate)
VALUES(?,?,?,?,?)";
$params=array(1,'Josh','josh101#coolsite.com','josh101','1978-11-02');
$db= new Mysql_database();
$response=$db->query($sql,$params);
Now here's what I want to do:
If the second argument is not provided, just run the query as it is.
Else check the elements of the array provided for their type and escape them properly then replace them in their appropriate positions in the pseudo-sql string provided.
The problem is that it seems that all the question marks get replaced by only the first element of the array:
Here's the code:
/*assuming I already have a function called create_array that well,
basically creates an array with n elements
specified in the first parameter and fills each element with the value provided in
the second parameter.*/
$toreplace = create_array(substr_count($sql, "?"),"?");
$sqlComplete = str_replace($toreplace, $params, $sql);
If I echo $sqlComplete I get this:
INSERT INTO users (id,name,email,username,birthdate)
VALUES(1,1,1,1,1)
What can I do so that each element of $params is put in its appropriate position in the sql string?
PS: Please don't tell me to just use codeigniter because I'm trying to challenge myself here a bit by building a project from scratch, I don't want to always depend on frameworks to get the job done.
Maybe just use MySQL prepared statements?
It can be done like this:
$params=array(1,'Josh','josh101#coolsite.com','josh101','1978-11-02');
$sql="INSERT INTO users (id,name,email,username,birthdate)
VALUES(?,?,?,?,?)";
foreach($params as $param)
{
$pos = strpos($sql, '?');
if($pos !== false)
{
$sql = substr_replace($sql,"'" . $param . "'",$pos,1);
}
}
echo $sql;
Outputs
INSERT INTO users (id,name,email,username,birthdate) VALUES('1','Josh','josh101#coolsite.com','josh101','1978-11-02')
This doesn't do any escaping, it just populates the values in the query. You'll need to add the escaping that's appropriate to the framework/DB API.

Does this work to stop sql injections

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());
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.
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.
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.
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.
To help you understand why your initial way was wrong Magic quotes in PHP
To help you understand why escaping has nothing to do with "data safety" yet not sufficient to protect your query: Replacing mysql_* functions with PDO and prepared statements
To help you understand when prepared statements not sufficient either and what to do in these cases: In PHP when submitting strings to the database should I take care of illegal characters using htmlspecialchars() or use a regular expression?
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

Escaping MySQL Query issue

I'm terribly bad at keeping MySQL queries straight, but that aside I have one query working for some data input, but not all. My guess is quotation marks getting escaped where they should be.
I have the entire query string get escaped at the same time. Is this bad practice or does it really matter?
Here's the query:
"INSERT INTO bio_manager_pubs(userid,category,citation,date,link,requests) VALUES ( ".
$userid.",'".
$_POST['category']."', '".
htmlentities($_POST['pub'])."',
FROM_UNIXTIME(".strtotime($_POST['date'])."),'".
$_POST['link']."',
0)"
In query:
Userid and requests are ints
Link and Category are Tiny Text (not sure if that's appropriate, but max is 255 char, so would VarChar be better?)
Date is a date (is it better to reformat with php or reformat with mysql?)
Citation is a text field
Any ideas?
Thanks
EDIT:
The answer to this question was posted four times there abouts where the issue was me escaping the entire query.
What was left out, and cause some confusion was the code surrounding the query.
It was like this
$db->query($query)
This where the function query was:
public function query($SQL)
{
$this->SQL = $this->mysqli->real_escape_string($SQL);
$this->result = $this->mysqli->query($SQL);
if ($this->result == true)
{
return true;
}
else
{
printf("<b>Problem with SQL:</b> %s\n", $this->SQL);
exit;
}
}
I just found a class that made life a bit simpler on smaller projects and stuck with it. Now, the issue I'm running into is removing $this->mysqli->real_escape_string($SQL); and adding in escapes elsewhere in the code.
I really don't see any sanitizing of your $_POST data, and there is really no need to run htmlentities before you insert into the database, that should be done when you take that data and display it on the page. Make sure to sanitize your posts!! Using mysql_real_escape_string() or preferably PDO with prepared statements.
If you are running mysql_real_escape_string() on this whole query, after you build it, than that is what is breaking it.
Use it on the individual posts, and / or cast variables that should only ever be numbers to integers.
Heres what I would change it to in your case:
$posted = $_POST;
foreach($posted as &$value)
$value = mysql_real_escape_string($value);
$date = strtotime($posted['date']);
$q = "INSERT INTO bio_manager_pubs(userid,category,citation,date,link,requests) VALUES
(
'{$userid}',
'{$posted['category']}',
'{$posted['pub'])}',
FROM_UNIXTIME({$posted['date']}),
'{$posted['link']}',
'0'
)";
I believe it is considered bad practice to build the entire query and then escape the whole thing. You should sanitize the inputs as soon as they enter the code, not after you've started using them to build your database interactions.
You'd want to sanitize each input, kind of like this:
$category = mysql_real_escape_string($_POST['category'])
And then you'd use the local variables, not the inputs, to build your SQL command(s).
Also, you may want to look into something like PDO for your data access, which manages a lot of the details for you.
I think you need to wrap each of your inputs in mysql_real_escape_string (only once!), not the whole query. Other than that it looks OK to me.
"INSERT INTO bio_manager_pubs(userid,category,citation,date,link,requests) VALUES ( ".
mysql_real_escape_string($userid).",'".
mysql_real_escape_string($_POST['category'])."', '".
mysql_real_escape_string(htmlentities($_POST['pub']))."',
FROM_UNIXTIME(".mysql_real_escape_string(strtotime($_POST['date']))."),'".
mysql_real_escape_string($_POST['link'])."',
0)"
Instead of escaping the entire SQL query (which can run the risk of breaking things), just escape the user's input:
$userid = mysql_real_escape_string($userid);
$cat = mysql_real_escape_string($_POST['category']);
$pub = mysql_real_escape_string($_POST['pub']);
$date = strtotime($_POST['date']);
$link = mysql_real_escape_string($_POST['link']);
$query = "INSERT INTO bio_manager_pubs(userid, category, citation, date, link, requests)"
." VALUES ($userid, '$cat', '$pub', $date, '$link', 0 );";
Well for a start you should avoid using data from external sources directly in a query, so I would rewrite the code so as not to use $_POST in your query. Even better if you can to use PDO or similar to escape your data. And I would avoid converting text with htmlentities before inserting it into your database. You're better off doing that after you pull it from the database as you will then be able to use that data in other (non-HTML) output contexts.
But in terms of inline code, do you have magic_quotes on?
Try something like this
if (get_magic_quotes_gpc()) {
$category = stripslashes($_POST['category']);
$pub = stripslashes($_POST['pub']);
$link = stripslashes($_POST['link']);
} else {
$category = $_POST['category'];
$category = $_POST['category'];
$category = $_POST['category'];
}
$category = mysql_escape_string( $category );
$pub = mysql_escape_string( $pub );
$link = mysql_escape_string( $link );
$sql = "
INSERT INTO bio_manager_pubs(userid,category,citation,date,link,requests) VALUES (
". $userid.",
'$category',
'$pub',
FROM_UNIXTIME(".strtotime($_POST['date'])."),
'$link',
0
)";
Turn off magic_quotes_gpc and use prepared statements.
With magic_quotes_gpc disabled, you don't end up with automatic escaping of input - and magic_quotes_gpc is deprecated anyway.
Use parameter binding prepared statements to avoid SQL injection rather than escaping characters. I personally suggest using PDO or MDB2 to talk to your db, but you can also do prepared statements with the mysqli driver. Note that the mysql driver is on the chopping block as well, so you soon will be forced to either use mysqli or an abstraction layer like MDB2.
I bet though that magic_quotes_gpc is your problem.

Categories