This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
Best way to stop SQL Injection in PHP
I have seen some of examples that use something called a PDO to make a query safe from sql-infection, or others that use real_escape, but they all seem to be incomplete or assume some knowledge. So I ask, take this simple update query and make it safe from sql-injection.
function updateUserName($id,$first,$last)
{
$qry = 'UPDATE user SET first = "'.$first.'", last = "'.$last.'" WHERE id = '.$id;
mysql_query($qry) or die(mysql_error());
}
Basically, you have to :
escape string, with mysql_real_escape_string
make sure integer really are integers ; for instance, using intval.
Which, in your specific case, would give something like this :
$qry = 'UPDATE user SET first = "'
. mysql_real_escape_string($first)
. ' ", last = "'
. mysql_real_escape_string($last)
. '" WHERE id = '
. intval($id);
Of course, this is considering that last and first are varchar, and that id is an integer.
As a sidenote : when an SQL error (this is also true for whatever kind of error you can thing about) occurs, you should not display a technical error message and just let the script die.
Your users will not understand that technical error message -- they won't know what to do with it, and it's not their problem.
Instead, you should log (to a file, for instance) that technical error message, for your own usage ; and display a nice "oops an error occured" page to the user.
This is the better query:
$qry = 'UPDATE user SET first = "'.mysql_real_escape_string($first).'", last = "'.mysql_real_escape_string($last).'" WHERE id = '.intval($id);
Use mysql_real_escape_string for strings and intval for numbers in your queries to make them safer.
mysql_real_escape_string + sprintf
$qry = sprintf('UPDATE user SET first = '%s', last = '%s' WHERE id = %d', mysql_real_escape_string($first), mysql_real_escape_string($last), $id);
I like it that way.
You could wrap all your variables in mysql_real_escape_string(). PDO (PHP Data Objects) is a better solution though, if it's available in your environment. You can find these docs here.
PDO will make your code more Object-Oriented and automate some of these tasks for you. Some good sample code of PDO preparing statements can be found deeper into the docs here.
Related
I am having a problem in my php file named JO-dashboard.php. It displays the error presented below the code.
Here is my code:
<?php
$link = connectToDB();
$strXML = "<chart caption='Factory Output report' subCaption='By Quantity' pieSliceDepth='30' showBorder='1' formatNumberScale='0' numberSuffix=' Units'>";
$strQuery = "select DISTINCT profile from vgprofile";
$result = mysqli_query($link, $strQuery) or die(mysqli_error());
if($result) {
while ($ors = mysqli_fetch_array($result)) {
$strQuery = "select sum(MT) as totalLM from tbljocreator where PROFILE =" . $ors['profile'];
$result2 = mysqli_query($link, $strQuery) or die(mysqli_error());
$getresult2 = mysqli_fetch_array($result2);
$strXML .= "<set label='" . $ors['profile'] . "' value ='" . $getresult2['totalLM'] . "' />";
mysqli_free_result($result2);
}
}
mysqli_close($link);
$strXML .= "</chart>";
echo renderChart("FusionCharts/Column3D.swf", "", $strXML, "JoCreator", 450, 300, false, true);
?>
THE ERROR IS IN:
$result2 = mysqli_query($link, $strQuery) or die(mysqli_error());
In the browser it shows:
Warning: mysqli_error() expects exactly 1 parameter, 0 given in C:\xampp\htdocs\LearningFusionCharts\MyFirstChart\JO-dashboard.php on line 29
the mysqli_error function requires a parameter. http://us3.php.net/mysqli_error
p.s clean up your code and using tabs :)
The initial problem
You have to pass the connection object to the function mysqli_error, like this:
$result = mysqli_query($link, $strQuery) or die(mysqli_error($link));
And this...
$result2 = mysqli_query($link, $strQuery) or die(mysqli_error($link));
Note: your code must have another problem that will be revealed after you do this. PHP wouldn't be executing the part of mysqli_error if there weren't an error in the query or something related to it.
The hidden problem
In fact, I have reasons to think* the problem is that $ors['profile'] is string, and therefore it should be between quotation marks in the query string:
$strQuery = 'select sum(MT) as totalLM from tbljocreator where PROFILE = "' . $ors['profile'] . '"';
*: This was confirmed in the comments. The error was:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near 'RIVETS' at line 1
In this case RIVETS is the value of $ors['profile'] and evidently it is an string, ergo it must go between quotation marks...but that doesn't mean it is safe.
SQL Injection
We could say that your code is correct, the same code will probably work is the data where different. Yet, since the values you are putting in the query string may not be entirely safe (even with the data comming from the database), you will have to escape the dangerous characters.
This is put in evidence by the error you got:
You have an error in your SQL syntax; check the manual that
corresponds to your MySQL server version for the right syntax to use
near '"CUTTING DISC 4""' at line 1
In this case, the variable $ors['profile'] got the string CUTTING DISC 4". This value is comming from the database and is causes a problem. It contains 4" meaning four inches, but Mysql sees the quotation marks (") and thinks that that is the end of the string, and tries to interpret whatever comes after the quotation marks as SQL.
If this input weren't from the database, but form the user... it would be worst... a malicious user could take adventage of it to execute arbitrary commands in the database. The potential of this kind of attack is overwhelming.
I recommend the video Hacking Websites with SQL Injection - Computerphile, it is a very good introduction to SQL injection for those beginners to web security, database security or information security in general. To learn more about what can be potentially be done with this kind of attack, read SQL Injection Walkthrough (DVWA) by Trenton Ivey.
Preventing SQL Injection - The old way
The old way to solve this problem is to escape the characters. SQL allows to do so by using the backslash character (\). So, in this example you would have to pass 4\" instead of 4". But that is the tip of the iceberg, there are plenty of security problems with it.
Something you could do for ease of migration is to declare a function to sanitize the data you send to the database, the idea is to escape any possibly treating character... in fact there is a function for that in PHP (mysql_real_escape_string):
$strQuery = 'select sum(MT) as totalLM from tbljocreator where PROFILE = "' . mysql_real_escape_string($ors['profile']) . '"';
The problems with the old way
But mysql_real_escape_string is deprecated and should not be used in new development (you would notice it is not form mysqli... ), this function has some quirks of itself too... for example there is no way to tell that function what character encoding you are using (it uses whatever the databases is using), and there has been reports of problems with it when using multibyte characters. That is the old way to solve this.
Here goes another recommendation: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets by Joel Spolsky. I understand if you don't want to read... get another video: Characters, Symbols and the Unicode Miracle - Computerphile
Preventing SQL Injection - The new and improved way
With that said, the correct solution is to migrate to prepared statements, they are not really that hard with mysqli, it would be something like this:
$strQuery = 'select sum(MT) as totalLM from tbljocreator where PROFILE = ?';
if($stmt = $link->prepare($strQuery))
{
//s for string
//i for integer
//d for double (or float)
$stmt->bind_param('s', $ors['profile']);
if (!$stmt->execute())
{
die mysqli_error($link);
}
}
else
{
die mysqli_error($link);
}
Read more about Prepared Statements at PHP.net.
Just change
mysqli_error()
to
mysqli_error($link)
in each of the places where it occurs.
ie 4th line:
$result = mysqli_query($link, $strQuery) or die(mysqli_error($link));
and 8th line:
$result2 = mysqli_query($link, $strQuery) or die(mysqli_error($link));
Replace
mysqli_error()
by
mysqli_error($link)
By the way, if the error message is as clear, you don't need to ask here. Just read the manual.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Best way to prevent SQL Injection in PHP
I just found that my website is vunerable.
Since it's connected to a DB and have functions like: Register, Change Password, Notices, etc... and SUPOSING it's fully vulnerable.
What should I look for into the code in order to start making it safe?
I mean, I did some researches and everywhere, everyone says different things about security.
"Use PDO."
"Use mysql_real_escape_string."
"Use addslashes."
What exactly should I look for??
"$_POST" and "$_GET" variables??
"$_SESSION" variables?
SQL querys?
$sql = "select * from user";
$sql = "update user set user="new_user_name";
$sql = "insert into user (user) values ('userid')";
What should I do in each case?
Please, help me to know what and where I must go.
Thank you.
Following are the points to be considered for making safe php application.
USE PDO or mysqli
Never trust any inputs. Consider every variable viz $_POST, $_GET, $_COOKIE, $_SESSION, $_SERVER as if they were tainted. Use appropriate filtering measure for these variables.
To avoid XSS attack use php’s builtin functions htmlentities,
strip_tags, etc while inserting the user input data into the
database.
Disable Register Globals in PHP.INI
Disable “allow_url_fopen” in PHP.INI
Don’t allow user to input more data than required. Validate input to
allow max number of characters. Also validate each field for
relevant datatypes.
Disable error reporting after Development period. It might give
information about database that’ll be useful to hackers.
Use one time token while posting a form. If token exist and matches
the form post is valid otherwise invalid.
Use parametrized database queries
Use stored procedures
You can google for each point for more details.
HOpe this helps
What you should look for: Any data send from the client/user. Sanitize/escape this data.
PDO can sanitize queries (using PDO::prepare) and supports multiple SQL systems.
For MySQL, use MySQLi. mysqli_real_escape_string is the function to use for sanitizing data if you are using MySQL.
None of the SQL queries you provided are actually vulnerable to SQL injection.
SQL injection vulnerabilities happen because SQL input is not properly escaped.
For example:
$sql = "select * from users where user_id =" . $_GET['user_id'];
Consider if I passed in the following:
http://some_server.com/some_page.php?user_id=123%20or%201=1
The query when executed would end up being:
select * from users where user_id = 123 or 1=1
To fix this, use parameterized queries:
$query = "select * from users where user_id = ?"
When you bind the user_id value to the query, the data access layer will escape the input string properly and the following would be executed:
select * from users where user_id = '123 or 1=1' which would not return any rows, preventing the injection
If using PHP and the mysql extension:
$sql = "select * from users where user_id = '" . mysql_real_escape_string($_GET['user_id']) . "'";
Keep in mind you need to escape ALL input that is going into a SQL query:
$sql = "select id_column from some_table where id = 1";
$stmt = mysqli_query($conn, $sql);
if($stmt === false) die(mysqli_error($conn) . "\n");
while($row = mysqli_fetch_assoc($conn, $stmt) {
$sql = "update some_other_table set some_value = 'new value' where some_column = '" . mysqli_real_escape_string($conn, $row['id_column']) . "'";
....
}
This is because values you select from the database might include characters that are not safe for execution in a SQL statement, like the name "O'Hara" or example.
}
I've been using PDO.
An example for that in your case:
<?php
$stmt = $dbh->prepare("insert into user (user) values (?)");
$stmt->bindParam(1, $name);
$name = 'ValueHere';
$stmt->execute();
?>
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Are mysql_real_escape_string() and mysql_escape_string() sufficient for app security?
So basically I have a qryName in the URL
eg: mysite.com/qryName=WHAT
if (isset($_GET['qryName']))
{
$qryName = mysql_real_escape_string(filter($_GET['qryName']));
}
$urldata = mysql_fetch_assoc(mysql_query("SELECT * FROM gangs WHERE ShortName = '" . $qryName . "' LIMIT 1"));
$urldata is the code so it pretty much selects from the database. Note that in the database, the qryName has no spaces, special chars etc..
Just wondering if that is exploitable?
It is safe since you properly escape the value - unless....
...you do not initialize the variable and have register_globals enabled. In that case someone can use a cookie or POST value to send you an arbitrary value for $qryName containing evil SQL statements.
But since you probably just posted a snipped and do initialize the variable before that if statement (you do, right?!), your code is safe. Consider using prepared statements (with PDO) though instead of escaping - they make your code more readable, too.
Why don't you add one extra piece of validation or take out the isset and check if it only contains letters for example
if(ctype_alpha($_GET['qryName'])) {
$qryName = mysql_real_escape_string(filter($_GET['qryName']));
}
http://php.net/manual/en/function.ctype-alpha.php
Have you considered using something like PDO? My understanding is that when using PDO and bound variables, SQL injection is not possible. There are also other advantages worth considering.
A similar PDO query would be:
$data=array($_GET['qryName']);
try {
$STH = $this->DBH->prepare('SELECT * FROM gangs WHERE ShortName = ? LIMIT 1');
$STH->execute($data);
while($row = $STH->fetch()) {
$var1=$row->FieldName;
}
}
catch(PDOException $e) {echo $e->getMessage();}
You add the variables to the array ($data) and they are bound in order to each question mark in the SQL statement.
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 's website.
mysql_query("UPDATE Scholarships2 SET Requirements2 = '$requirements2'
WHERE scholarshipID = '$sID'")
or die("Insert Error1: ".mysql_error());
I read other Stackoverflow questions/answers on this subject but cannot find the reserved word I am using.
$sID is just an int while, $requirements2 is
$regex = '/<h4>Requirements<\/h4>([\n\n\n]|.)*?<\/table>/';
preg_match_all($regex,$data,$match);
$requirements2 = $match[0][0];
for the right syntax to use near 's website
This means it's complaining about the bit of your query that is 's website. "Where is that bit in your query?", I hear you ask.
Well, one of those variables in there contains something like Bob's website and the fact that you're blindly injecting that into your query will give you something like:
UPDATE Scholarships2 SET Requirements2 = 'Bob's website' ...
This particular query will not go down well with the SQL parser :-)
Other possibilities that don't immediately choke the parser will also not go down well with your customer base when little Bobby Tables steals or deletes your credit card database.
See this link for a fuller explanation and strategies for avoidance. In your case, that's probably going to involve mysql-real-escape-string.
In other words, you'll need something like:
mysql_query(
"UPDATE Scholarships2 SET Requirements2 = '" .
mysql_real_escape_string($requirements2) .
"' WHERE scholarshipID = '" .
mysql_real_escape_string($sID) .
"'"
) or die("Insert Error1: ".mysql_error());
As an aside, if $sID is just an integer (and not subject to injection attacks), you could probably remove the quotes from around it. I don't think it matters with MySQL (due to its "everything is a string" nature) but your query won't be portable to other DBMS'.
It depends on the values you have in your variables
Depending on the data type here is what you can do
$requirements2 = mysql_real_escape_string($requirements2); // escape string
$sID = (int)$sID; // force integer
the problem is if you have a string in your $requirement and it contains a single quote ' it will break your sql statement.
Here is something i often do to organize my code.
$sql = "UPDATE Scholarships2 SET Requirements2 = '%s'
WHERE scholarshipID =%d";
$sql = sprintf($sql,
mysql_real_escape_string($requirements2),
(int)$sID
);
Are you just taking form fields in from a POST or AJAX query? It sounds like you have a string containing 's website.
Make sure you run your code though mysqli_escape_string.
You need to escape whatever input you are getting in $requirements2
You can do this by
$req2=mysql_real_escape_string($requirements2);
mysql_query("UPDATE Scholarships2 SET Requirements2 = '$req2'
WHERE scholarshipID = '$sID'")
or die("Insert Error1: ".mysql_error());
This will escape any special characters like the apostrophe found in $requirements2
The problem is that your $requirements2 variable contains a single quote (the error message shows it when it says near 's website - presumably you're inserting something like welcome to Sal's website). When MySQL encounters this character, it's interpreting it as the termination of the entire string.
For example, if you substituted the phrase Welcome to Sal's website into your query where $requirements2 currently is, your query would look like this:
UPDATE Scholarships2 SET Requirements2 = 'Welcome to Sal's website'
As you can see, this results in a quoted string Welcome to Sal with the rest of the string hanging off the end not a part of anything. That's the part that the error is complaining about.
You really need to switch to PDO and prepared statements, otherwise you're leaving yourself wide open to these types of errors, including SQL injection which is a Very Bad Thing.
Prepared statements allow you to specify queries with placeholders where dynamic data can be placed. This extra data is then passed to PDO in a separate function where PDO/the database can determine the best way to sanitize it so that it doesn't get misinterpreted as part of the query structure itself.
Good Morning everyone,
I am using an update command in php to update data in mysql. This is my code:
$sql=mysql_query("UPDATE blpublication SET JournalName = '$_POST[journal]', AcceptanceDate = '$_POST[acceptancedate]', PublishedDate = '$_POST[publisheddate]', Comment = '$_POST[comment]'
WHERE JobNo = '$_POST[jobno]'");
if (!mysql_query($sql,$con))
{
die('Error: ' . mysql_error());
}
echo "record Updated";
It does updates the field but, it gives me the following error. And i can not figure it out why am i getting this error.
"Error: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1' at line 1"
Can you help me in this
Best
Zeeshan
Can you tell us what the exactly output of $sql is? By the way, BIG security hole there. You should always escape query inputs namely:
$journal = mysql_real_escape_string($_POST['journal']);
$acceptance_date = mysql_real_escape_string($_POST['acceptancedate']);
$publish_date = mysql_real_escape_string($_POST['publisheddate']);
$comment = mysql_real_escape_string($_POST['comment']);
$job_no = intval($_POST['jobno']); // assuming jobNo is a number
$sql = <<<END
UPDATE blpublication
SET JournalName = '$journal',
AcceptanceDate = '$acceptance_date',
PublishedDate = '$publish_date',
Comment = '$comment'
WHERE JobNo = $jobno
END;
mysql_query($sql);
if (mysql_error()) {
die("Error executing query '$sql': " . mysql_error());
}
echo "record Updated";
I would sanitize your input first. This could lead to some very nasty errors such as what you are experincing and malicious attacks. Look up SQL Injection.
I think the problem is that you're running mysql_query twice. The first time it works and returns 1 (true), which you assign to $sql. Then you call mysql_query again, passing $sql (which equals 1). Of course "1" is not a valid SQL query, so you get the syntax error.
I wholeheartedly agree that you must sanitize those inputs!
Similar to the following post, i believe when you have any object or array syntax, you need to put in braces.
SET JournalName = '${_POST[journal]}'
edit: and yes, as others pointed out you are risking sql injection.
First of all, your code is prone to SQL injection, escape your POST values:
$journal = mysql_real_escape_string($_POST['journal']);
And to actually debug your query, we need the query itself. Add an echo() statement before the actual execution of the query and post the result, the POST values possibly contain some unexpected value.
Your general UPDATE syntax looks ok, except for the obvious injection possibilities, but you need to output $sql. One of your variables probably has a quote in it or some other issue like that....
Looking at the SQL UPDATE statement in your code, one thing leaps out at me. The table name is blpublication, are you maybe missing a 't', i.e. tblpublication?
Also you should really sanitise your input, otherwise you're going to be a victim of a SQL injection attack.
Try concatenating the $_POST values. Im not sure if including them without quoting the key is possible?
$sql= mysql_real_escape_string("UPDATE blpublication SET JournalName = '".$_POST['journal']."', AcceptanceDate = '".$_POST['acceptancedate']."', PublishedDate = '".$_POST['publisheddate']."', Comment = '".$_POST['comment']."'
WHERE JobNo = '".$_POST['jobno']."'");
$result = mysql_query($sql);
Note: mysql_* commands are depreciated. You should switch over to mysqli_*.