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.
Related
I am having an issue with this not running at all when the information is submitted, I believe that I have the syntax wrong.
if ($_POST['note'] != $player->note_text) {
$message = 'Admin '.$user.' has added the note ('.$_POST['note'].') to '.$player->name.'('.$pid.')';
logIt($user, $message, $dbcon);
$note = $_POST['note'];
$note = '"'.$note.'"';
$UpdateN = "INSERT INTO notes (uid, staff_name, name, alias, note_text, warning) VALUES ('$_POST[hidden]', '$user', '$player->name', '$player->aliases', '$note','$_POST[warn]')";
$UpdateN2 = "INSERT INTO players WHERE `playerid` = $_POST[hidden] (warning) VALUES ('$_POST[warn]')";
mysqli_query($dbcon, $UpdateN, $UpdateN2);
The new line I added which seems to have broken it is '$UpdateN2'.
I am not sure if the new line has broken the statement, since I am new to PHP and mysqli any pointers to forums or websites that I can learn and understand this in a more detailed way I would appreciate.
Edit: I have since moved from using mysqli to PDO, I strongly suggestion that anyone willing to start using MYSQL commands with PHP to have a look at this: http://wiki.hashphp.org/PDO_Tutorial_for_MySQL_Developers
I started reading this and testing things out, I find this much more easier but also it looks a lot cleaner and understandable when reading it back after a few days have passed.
In keeping with the mysqli procedural style in the original, using prepared statements with bind placeholders, something like this:
$UpdateN = 'INSERT INTO notes (uid, staff_name, name, alias, note_text, warning)'
. ' VALUES ( ?, ? , ? , ? , ? , ? )';
$UpdateN2 = 'UPDATE players SET warning = ? WHERE playerid = ? ';
if( $sth = mysqli_prepare($dbcon,$UpdateN) ) {
mysqli_stmt_bind_param($sth,'ssssss'
,$_POST['hidden']
,$user
,$player->name
,$player->aliases
,$_POST['note']
,$_POST['warn']
);
if( mysqli_stmt_execute($sth) ) {
// statement execution successful
} else {
printf("Error: %s\n",mysqli_stmt_error($sth));
}
} else {
printf("Error: %s\n",mysqli_error($dbcon));
}
if( $sth2 = mysqli_prepare($dbcon,$UpdateN2) ) {
mysqli_stmt_bind_param($sth2,'ss'
,$_POST['warn']
,$_POST['hidden']
);
if( mysqli_stmt_execute($sth2) ) {
// statement execution successful
} else {
printf("Error: %s\n",mysqli_stmt_error($sth2));
}
} else {
printf("Error: %s\n",mysqli_error($dbcon));
}
If it was me, I'd just make two separate calls to mysqli_query, one for each of your separate queries. PHP has historically been very wary of permitting multiple queries in a single function call, because of possible sql injection vulnerabilities.
On a related note, you need to sanitize your input. $_POST should never, ever, ever appear directly in a mysql query string, because your post data might -actually be something like ')"; DROP TABLE users;'.
Finally, you're using a WHERE clause on an insert. That's probably breaking your query. You should take a couple of days and research how and why that's breaking your query, and how and why to write proper sql queries. Doing so will add value to your company, because your company is less likely to suffer a catastrophic data breach, and it will add value to you, because you'll be a better SQL coder.
Edit: and in the time it took me to write this, three different people made each of those points. LOL.
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.
I'm trying to insert form data into a MySQL 4.1 DB. The problem I'm having is form fields that include spaces get truncated before insertion. The POST variables are complete, spaces and all. Just being cut off somewhere. For instance, "South Lake Tahoe" is inserted simply as "South". Zip codes and telephone numbers with dashes are also fine. The site I'm working on is hosted by Yahoo Small Business, and they're still using MySQL 4.1. I don't know if that is the problem, but I do know I never had issues doing this with MySQL 5+. The user fills out a form to add a new member. Upon Submit, the form data is POSTED to another page for processing:
$k = array();
$v = array();
$first_name = $_POST['first_name'];
$last_name = $_POST['last_name'];
$result = mysql_query("SELECT * FROM members WHERE first_name='$first_name' AND last_name='$last_name'");
if(mysql_num_rows($result)>0){
mysql_free_result($result);
exit("Duplicate User in Database");
}
mysql_free_result($result);
array_pop($_POST);//Don't need the Submit value
foreach($_POST as $key=>$value){
array_push($k, "$key");
array_push($v, "$value");
}
$fields = implode(", ", $k);
$values = array();
foreach($v as $key=>$value){
array_push($values, '"'.$value.'"');
}
$values_string = implode(", ", $values);
$result = mysql_query("INSERT INTO members($fields) VALUES($values_string)");
I'm sure there are better ways of doing this, but I'm still on the way up the learning curve. Please point out any obvious flaws in my thinking.
Any suggestions are greatly appreciated.
EDIT: The field types in MySQL are correct and long enough. For example, the field for City is set as VARCHAR(30).
Thanks much,
Mark
This code is horrifically insecure - you're taking user-supplied values and plopping them directly into your SQL statements without any sanitization. You should call http://php.net/manual/en/function.mysql-real-escape-string.php on anything you insert into a query this way (parameterized queries with PDO are even better).
You also make some assumptions, such as $_POST always being ordered a certain way (is that guaranteed?) and that you have exactly as many elements in your form as you have fields in your table, and that they're named identically. The code as it's written is the kind of thing a lot of beginning programmers do - it feels efficient, right? But in the end it's a bad idea. Just be explicit and list out the fields - e.g.
$field1 = $_POST['field1'];
$field2 = $_POST['field2'];
$sql = "insert into mytable (field1, field2) values ('" . mysql_real_escape_string($field1) . "', '" . mysql_real_escape_string(field2) . "')";
mysql_query($sql);
I haven't touched on why stuff would cut off at the first space, as this would imply that your code as you have it presented is salvageable. It's not. I get the feeling that reworking it as I described above might make that problem go away.
<?php
// Remember to always escape user input before you use them in queries.
$first_name = mysql_real_escape_string($_POST['first_name']);
$last_name = mysql_real_escape_string($_POST['last_name']);
$result = mysql_query("SELECT * FROM members WHERE first_name='$first_name' AND last_name='$last_name'");
if (mysql_num_rows($result) > 0) {
mysql_free_result($result);
exit("Duplicate User in Database");
}
mysql_free_result($result);
// I removed your loop around $_POST as it was a security risk,
// and could also become non-working. (What would happen if the order
// of the $_POST keys were changed?)
// Also the code become clearer this way.
$result = mysql_query("INSERT INTO members(first_name, last_name) VALUES('$first_name', '$last_name')");
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.
Should be a simple question, I'm just not familiar with PHP syntax and I am wondering if the following code is safe from SQL injection attacks?:
private function _getAllIngredients($animal = null, $type = null) {
$ingredients = null;
if($animal != null && $type != null) {
$query = 'SELECT id, name, brief_description, description,
food_type, ingredient_type, image, price,
created_on, updated_on
FROM ingredient
WHERE food_type = \'' . $animal . '\'
AND ingredient_type =\'' . $type . '\';';
$rows = $this->query($query);
if(count($rows) > 0) {
etc, etc, etc
I've googled around a bit and it seems that injection safe code seems to look different than the WHERE food_type = \'' . $animal . '\' syntax used here.
Sorry, I don't know what version of PHP or MySQL that is being used here, or if any 3rd party libraries are being used, can anyone with expertise offer any input?
UPDATE
What purpose does the \ serve in the statement?:
WHERE food_type = \'' . $animal . '\'
In my googling, I came across many references to mysql_real_escape_string...is this a function to protect from SQL Injection and other nastiness?
The class declaration is:
class DCIngredient extends SSDataController
So is it conceivable that mysql_real_escape_string is included in there?
Should I be asking to see the implementation of SSDataController?
Yes this code is vulnerable to SQL-Injection.
The "\" escapse only the quote character, otherwise PHP thinks the quote will end your (sql-)string.
Also as you deliver the whole SQL-String to the SSDataControler Class, it is not possible anymore to avoid the attack, if a prepared string has been injected.
So the class SSDataControler is broken (vulnerable) by design.
try something more safe like this:
$db_connection = new mysqli("host", "user", "pass", "db");
$statement = $db_connection->prepare("SELECT id, name, brief_description, description,
food_type, ingredient_type, image, price,
created_on, updated_on
FROM ingredient
WHERE food_type = ?
AND ingredient_type = ?;';");
$statement->bind_param("s", $animal);
$statement->bind_param("s", $type);
$statement->execute();
by using the bind method, you can specify the type of your parameter(s for string, i for integer, etc) and you will never think about sql injection again
You might as well use mysql_real_escape_string anyway to get rid of anything that could do a drop table, or execute any other arbitrary code.
It doesn't matter where in the SQL statement you put the values, at any point it can have a ';' in it, which immediately ends the statement and starts a new one, which means the hacker can do almost anything he wants.
To be safe, just wrap your values in mysql_real_escape_string($variable). So:
WHERE Something='".mysql_real_escape_string($variable)."'
$animal can be a string which contains '; drop table blah; -- so yes, this is vunerable to SQL injection.
You should look into using prepared statements, where you bind parameters, so that injection cannot occur:
http://us3.php.net/pdo.prepared-statements
It is vulnerable. If I passed: '\'; DROP TABLE ingredient; SELECT \''
as $type, poof, goodbye ingredient table.
If its a private function, kind of. If you're concerned about people with access to the source injecting SQL, there are simpler ways to accomplish their goal. I recommend passing the arguments to mysql_real_escape_string() before use, just to be safe. Like this:
private function _getAllIngredients($animal = null, $type = null) {
$animal = mysql_real_escape_string($animal);
$type = mysql_real_escape_string($type);
...
}
To be extra safe, you might even pass it to htmlentities() with the ENT_QUOTES flag instead - that would also help safeguard against XSS type stuff, unless you're putting the contents of those DB entries into a <script> tag.
But the safest thing you can do is write your own sanitizing function, which would make the best of various techniques, and also allow you to easily protect against new threats which may arise in the future.
Re: UPDATE
The \'' serves to enclose the variable in quotes, so that when it goes through to SQL, nothing is broken by whitespace. IE: Where Something=Cold Turkey would end with an error, where Something='Cold Turkey' would not.
Furthermore, the class extension won't affect how you put together MySQL Statements.
If the the user or any 3rd party has anyway of injecting a value of $animal into your system (which they probably do), then yes it is vunerable to sql injection.
The way to get around this would be to do
private function _getAllIngredients($animal = null, $type = null) {
$ingredients = null;
if($animal != null && $type != null) {
$query = 'SELECT id, name, brief_description, description,
food_type, ingredient_type, image, price,
created_on, updated_on
FROM ingredient
$rows = $this->query($query);
if(count($rows) > 0) {
if($rows['animal'] == $animal && $rows['ingredient_type'] == $type) {
Note: I removed WHERE statements from sql and added if statements to loop