I have no idea about PHP security, but if I add an ' to the input in my POST method form.
I'm getting the following message:
Warning: mysql_fetch_object(): supplied argument is not a valid MySQL result resource in /usr/local/www/login.php
Is that a SQL injection? If so, how it can be abused by the "hackers" ?
That means you're vulnerable to SQL injection, and your code is not doing sufficient checking for errors.
An absolute barebones "safe" bit of code would be:
<?php
... connect to db ...
$stringval = mysql_real_escape_string($_GET['param']);
$sql = "SELECT somefield FROM sometable WHERE otherfield='$stringval'";
$result = mysql_query($sql) or die(mysql_error());
better yet is to stop using the mysql functions and switch to PDO and parameterized queries. They handle the injection problems for you automatically.
The root cause of your error message is that your query has caused a syntax error. When a query fails outright like that, mysql_query() returns a boolean FALSE value, not a statement handle.
Since you lack any kind of error checking, you blindly took that boolean false and passed it on to the fetch function, which has rightfully complained that you didn't provide a result handle.
You should escape any user input before passing it to mysql. Use the PHP function mysql_real_escape_string() to escape any user input before adding it to your query. Here is the link to PHP manual for mysql_real_escape_string()
Update: Yes, what others are saying about using prepared statements or mysqli is much better that using the mysql extension.
Here are a few links on MySQL Injection which I found:
http://www.php.net/manual/en/security.database.sql-injection.php
http://25yearsofprogramming.com/blog/2011/20110205.htm
https://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
Related
I have an Application with PHP 5.3.29 and MySQL 5.6.35.
I used SQLQUERY to execute SQL instrucctions, then change to PDO with prepared Statements to avoid SQL-i, but whe i test my app with ZAP 2.6.0, i can confirm that the SQL-I still happens, despite the use of "PDO" and "prepare".
I activated the general log at MySQL and looked for all statements that were executed.
My code is:
function cerrar_sesion($usuario) {
$pdo = new
PDO("mysql:"."host=".DB_SERVIDOR.";"."dbname=".DB_BASEDATOS,DB_USUARIO, DB_CLAVE);
$query = $pdo->prepare('UPDATE ADMIN_USUARIO SET USERID=\' \' WHERE C_USUARIO= :usuario');
$query->bindParam(':usuario',$usuario,PDO::PARAM_INT);
$query->execute();
$pdo = null;
.........
}
Checking the DB log i see the parameter "C_USUARIO" changed, the following 3 lines were extracted from MySQL Log:
227726 Query UPDATE ADMIN_USUARIO SET USERID=' ' WHERE C_USUARIO= '54/2' 227730 Query UPDATE ADMIN_USUARIO SET USERID=' ' WHERE C_USUARIO= '108/2' 227732 Query UPDATE ADMIN_USUARIO SET USERID=' ' WHERE C_USUARIO= '108/2'
Note the values for C_USUARIO should't have "/2", that was injected by ZAP
I expected PDO to prevent the injection, but this wasn't the case, how can i do this using PDO?
Please help me, i´ll apreciate it.
By default, PDO "emulates" prepared statements, by interpolating the bound variables into your SQL query string, and then executing that SQL directly, without using parameters.
PDO does apply correct escaping as it interpolates your variables in the query, so it is safe with respect to SQL injection.
If you want real parameterized queries, disable emulation:
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
See http://php.net/manual/en/pdo.setattribute.php for more information.
If you disable emulation, your MySQL query log will show the PREPARE and EXECUTE as separate steps. But MySQL will also log the full query including parameter values. This is also safe, it's just a convenience that MySQL does for the sake of logging, because it's useful to show the query with values. See example in my answer to https://stackoverflow.com/a/210693/20860.
I'm currently working with PHP 5.4.x and SQL Server 7 and I'm having TONS of issues with the PDO object for the ODBC Driver (Which is the only one that works on Sql Server 7), Statements throw errors everywhere ....
I finally got it working using PDO::query() method, BUT I need to escape the Input .... And PDO::quote IS NOT WORKING, I red the Documentation on php pdo docs about PDO and it says that PDO::quote is Not well implemented on PDO_ODBC, which might explain why im getting errors.
For Example: this
$escapedString = $pdoObject->quote($myQueryString);
returns False, it does not return the escaped string.
That been said,
Do you know a good way to escape input to prevent SQL INJECTION???
PS: Due to driver issues (old tech) I CANNOT Trust in SQL Statements, so is not an option.
Any ideas??
EDIT:
For Example. This does not work
getQueryFromFile is only retrieving a query from a file.
and SqlServerPdo is just a wrapper class I wrote over the PHP PDO so I get the connection as a Singleton
For the Record, the query actually WORKS, it has been tested on the Sql Server Engine
$conn = SqlServerPdo::connect();
$query = SqlServerPdo::getQueryFromFile('STUDENTS_FIND');
$statement = $conn->prepare($query);
$statement->bindParam(':id', $id, PDO::PARAM_INT);}
$statement->execute();
This throws the error:
text is incompatible with int (SQLExecute[206] at ext\pdo_odbc\odbc_stmt.c:133)
It seems as if the statement is treating the :id param as a text, not as an INT.
bindValue returns the same error
I am trying to bind parameters to an UPDATE statement using ODBC in PHP but the SQL statement is failing and I cannot for the life of me work out why. I've tried Googling but there seems to be very little info regarding using ODBC with PHP as opposed to the likes of MySQLi and PDO.
Most examples I've found with parameter binding use a SELECT statement but as far as I can tell that shouldn't make a difference. The closest answer I've found was here on stackoverflow. As far as I can see they are doing what I'm doing but I keep getting an error. Here is my code:
$updQuery = "UPDATE Demographic SET dmg_FirstName=? WHERE dmg_ID=?";
$update = odbc_prepare($connect, $updQuery);
$fname = $_POST['firstname'];
$pID = 145100007;
$updResult = odbc_execute($update, array($fname, $pID)) or die (odbc_errormsg());
Here's the error I keep getting on the above code:
Warning: odbc_execute(): SQL error: [Microsoft][ODBC Driver Manager] SQL data type out of range, SQL state S1004 in SQLBindParameter in C:\xampp\htdocs\work\ajaxdd.php on line 44
The code works when I remove the parameter binding so if worst comes to the worst I can try to sanitise the data as best I can but that's obviously not preferable.
This probably means that you're trying to insert an ID that is higher than that integer column allows. Try verifying if this is the case first. What is the type of dmg_ID? 145100007 is a rather high number so I suspect this might be the culprit.
I have read this:
will help you NOT against injection.
Beause escaping is just a string formatting facility, not injection preventer by any means.
Go figure.
However, escaping have something in common with prepared statements:
Them both doesn't guarantee you from injection if
you are using it only against notorious "user input", not as a strict rule for the building ANY query, despite of data source.
in case you need to insert not data but identifier or a keyword.
On the following Post: Are dynamic mysql queries with sql escaping just as secure as prepared statements?
So my question is that using:
$Var = "UserInput Data Possible SQL Injection";
$mysqli->real_escape_string($Var);
does not provide protection against SQL Injection?
I want to use $mysqli->query(); so I can use fetch_array(MYSQLI_ASSOC); Because to be frank, I have no idea how to fetch the results as an array after using a prepared statement.
So If I have this in my Database Connection:
$STD = new mysqli('localhost', 'root', 'xx', 'xx');
$STD->set_charset('utf8');
if ($STD->connect_error) {
die("Standard Access Has Been Revoked. Please Contact Administration");
}elseif (!$STD){
die ("Other problem With Connecting To Database, Please Contact Administration");
}
as stated in the manual for real_escape_string
http://php.net/manual/en/mysqli.real-escape-string.php
The above lists:
Caution
Security: the default character set
The character set must be set either at the server level, or with the API function mysqli_set_charset() for it to affect mysqli_real_escape_string(). See the concepts section on character sets for more information.
Which links to: http://php.net/manual/en/mysqli.set-charset.php
My overall question can split into three options, the first would be asking for a fetch_array() equlivant for prepared statements, which will provide full SQL injection prevention due to prepared statements sending data as raw.
The first question in this format follows:
I'm using a Query as:
$GetCompletedQuery = $STD->query("SELECT Status FROM UserCompletion WHERE `UserID`=' ". $STD->real_escape_string($_SESSION['UID']) ."'");
$GetCompletedArray = $GetCompletedQuery->fetch_array(MYSQLI_ASSOC);
Which returns:
Array ( [Status] => 1 )
But using prepared statements:
$GetCompletedQuery = $STD->prepare("SELECT Status FROM UserCompletion WHERE `UserID`=?");
$GetCompletedQuery->bind_param('i', $_SESSION['UID']);
$GetCompletedQuery->execute();
$GetCompletedArray = $GetCompletedQuery->fetch_row;
print_r($GetCompletedArray);
Which returns:
Fatal error: Call to a member function fetch_row() on a non-object in /var/www/New/API/Constants.php on line 17
The same appears when I try fetch_array() which I know cannot be used with prepared statements.
So what would be the option for using prepared statements?
Second Question
If I use My Usual Query as:
$GetCompletedQuery = $STD->query("SELECT Status FROM UserCompletion WHERE `UserID`=' ". $STD->real_escape_string($_SESSION['UID']) ."'");
which enabled me to use fetch_array(); is data properly secured from SQL injection?
Third Question:
Should I be escaping/protecting from SQL injection for a $_SESSION['UID']; as this is assigned in the following manor:
$InnerJoinQuery = $STD->query("
SELECT Users.ID, Users.Username, Users.Password, UserInformation.LastName, UserInformation.Firstname, UserInformation.DOB
FROM Users
INNER JOIN UserInformation
ON Users.ID = UserInformation.UserID WHERE Users.Username = '".$_SESSION['real_name']."'");
$InnerJoinArray = $InnerJoinQuery->fetch_array(MYSQLI_ASSOC);
$_SESSION['UID'] = $InnerJoinArray['ID'];
$_SESSION['Password'] = $InnerJoinArray['Password'];
$_SESSION['Firstname'] = $InnerJoinArray['Firstname'];
$_SESSION['LastName'] = $InnerJoinArray['LastName'];
$_SESSION['DOB'] = $InnerJoinArray['DOB'];
This snippet explained:
User Logs in with username & password, the file gets information from the database based on $_SESSION['real_name'];
and adds to the $_SESSION array with the results, adding each into a different key.
The question for this chunk is should I even be escaping/protecting from SQL injection when the $_SESSION['UID']; is assigned through the database based on $_SESSION['real_name'];
Thankyou for your time for reading over this massive chunk.
http://php.net/manual/en/mysqli-stmt.get-result.php
Yes, but it is very bad practice:
it will help you in this case but only in this case and deceive with anything else
manual escaping is just silly, better let driver to do it for you
YES, because there is no such thing like SQL injection but improper formatting ONLY
is that using $mysqli->real_escape_string($Var); does not provide protection against SQL Injection?
I didn't change my mind: sure, it doesn't.
It will do only if you enclose the resulting value in quotes (and set proper encoding using mysqli_set_charset() to be strict).
Look, SQL injection not something essential, existing on it's own, but it's rather mere a consequence. A consequence of improperly formatted query.
When creating a query, you have to properly format every part of it. Not because of whatever "injection" but for the sake of it. When you're going to insert a string into query, you HAVE to put it into quotes, or you will get a syntax error. When you're going to insert a string into query, you HAVE to escape these quotes were used to delimit this string, or you will get a syntax error. And so on. It is proper formatting that should be your concern, not scaring tales about injection. And as long as you have every dynamic query part properly formatted according to it's type - no injection ever could be possible
So, the source of variable or it's value should never be your concern. But only it's place in the query:
strings have to be enclosed in quotes and have these quotes escaped.
numbers have to be cast to it's type.
identifiers have to be enclosed in backticks and have these backticks doubled
When it's going for the static part of the query, hardcoded in the script, we don't use such strict standards - say, we're not enclosing every identifier in backticks.
But when it's going for the dynamical part of the query, applying formatting rules should be strict rule, as we cannot know variable content for sure.
By the way, there is another way to format your strings and numbers - prepared statements. It is not as convenient as it should be, but because it is using placeholders to represent your data in the query, it it recommended to use over silly manual formatting.
Here is the mysql insert the I am running in php. I have removed the part giving the error but then I get a error on the next piece. I am not seeing what is diffrent to cause the error.
$fields="adv_exchange SET synum='".$synum."', worknum='".$_POST['worknum']."', user_id='".$current_user->ID."', f_name='".$current_user->user_firstname."', l_name='".$current_user->user_lastname."', email='".$current_user->user_email."', regnum=".$_POST['regnum'].", item='".$item."', qsver='".$_POST['qsver']."', flashrom='".$_POST['flashrom']."',expansion='".$_POST['board']."', rdisplay='". $_POST['rdisplay']."', screen_model='".$_POST['screen_model']."', p_hardware='".$_POST['cable']."', pcolor='".$_POST['pcolor']."', pname='".$_POST['pname']."', kboard='".$_POST['kboard']."', ip='".$_POST['ip']."', reg_name='".$_POST['reg_name']."', mem=".$_POST['mem'].", dt_server='".$_POST['dt_server']."', alert='".$_POST['alert']."', ows='".$_POST['ows']."', w_date='".$_POST['w_date']."', flashromver='".$_POST['flashromver']."', s_size='".$_POST['s_size']."', mag='".$_POST['mag']."', rcard='".$_POST['rcard']."', kvsid=".$_POST['kvsid'].", finger='".$_POST['finger']."', stand_alone='".$_POST['stand_alone']."', standards='".$_POST['standards']."', profile='".$_POST['profile']."', man_date='".$_POST['man_date']."', l_sn='".$_POST['l_sn']."', misc='".$_POST['misc']."', problem='".$_POST['problem']."'";
then $query = "insert into $fields";
I receive back
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 ' item='JS900CV', qsver='', flashrom='',expansion='', rdisplay='', screen_model='' at line 1
Blockquote
if I echo the $query I get this:
insert into adv_exchange SET synum='SY5135', worknum='123456', user_id='2', f_name='REMOVED', l_name='REMOVED', email='REMOVED', regnum=, item='JS900CV', qsver='', flashrom='',expansion='', rdisplay='', screen_model='', p_hardware='', pcolor='', pname='', kboard='', ip='192.168.1.16', reg_name='', mem=, dt_server='', alert='', ows='', w_date='', flashromver='', s_size='', mag='', rcard='', kvsid=3, finger='', stand_alone='', standards='', profile='', man_date='', l_sn='', misc='misc test\r\n', problem='gen test'
Depending on what I enter in the error is changing spots in my statement. Not all fields are used the form is dynamic that is supplying the data so the fields are dependent on what options are selected. On a side note in case of concern about using $_POST to insert directly into mysql, I sanitize the array first. Any help would be greatly appreciated.
Look at regnum=,. You don't provide a value for regnum. Either leave it out entirely or set it to an appropriate value.
You're using a very, very bad approach to MySQL databases: manually creating the queries. You should really use prepared statements instead: this issue will be resolved as well.
Don't use mysql_* functions, use PDO instead.
Your code would look like this (simplified):
// This holds the query
$statement = $pdo->prepare('INSERT INTO adv_exchange SET synum=?, worknum=?, etc=?, problem=?');
// This executes it with the given arguments. It's 100% injection-proof and safe. In fact, it's also faster.
$statement->execute(array($synum, $_POST['worknum'], $_POST['therest'], $_POST['problem']));
regnum=".$_POST['regnum']." is causing the problem. When it is undefined, you get regnum=, in the SQL query
A bigger concern is that you are not escaping your inputs. Either use mysql_real_escape_string around them, or better, use prepared statements.
You need to SET regnum=SOMETHING.
Currently it's empty.