I have a table that contains name of movies and other things and in my php page I want to select some of that movies..
$sql3 = "SELECT * FROM Movies where Movies.nameM='{$row['nameM']}';";
This query crashes when the nameM (name of movie) has an apostrophe in its name :/
How can I change this to work well?
Thanks for your help
You may try:
$sql3 = "SELECT * FROM Movies where Movies.nameM='".mysqli_real_escape_string($row['nameM'])."';";
And if you are using the old and deprecated mysql_* functions:
$sql3 = "SELECT * FROM Movies where Movies.nameM='".mysql_real_escape_string($row['nameM'])."';";
As Spudley said you should R&D more. Just to make it a few easier for you
You may use mysql(i)_ real escape functions but if you're using a framework works on top of PDO you don't have a mysql(i)_* connection and can't escape strings using them
i have seen this problem previously on yii or f3 or ...
Mostly the frameworks support the param safe injection.
\Framework::Query("SELECT .... WHERE column=:param", array(':param'=>$value));
But some times you may need to escape the string value manually. To do that with PDO you can acquire the pdo object and use the :
substr($pdo->quote($string, , \PDO::PARAM_STR), 1, -1)
The only note is that the ->quote() also puts the apostrophes around the result which they can get wiped using substr.
Edited to make the codes clear
Related
Here is my code below:
$studentTalking = mysql_real_escape_string($_POST['studentTalking']);
//Finally, we can actually the field with the student's information
$sql = <<<SQL
UPDATE `database` SET
`studentName`='$studentName',
`studentEmail`='{$data['studentEmail']}',
`studentPhone`='{$data['studentPhone']}',
`studentID`='{$data['studentID']}',
`studentTalking`= '{$studentTalking}',
`resume` = '{$data['resume']}'
WHERE `id`={$data['date_time']} AND (`studentName` IS NULL OR `studentName`='')
SQL;
I am trying to use the mysql_real_escape_string to allow apostrophes entered into our form by the user to go to the database without breaking the database, however the data will either go through as null or the apostrophe will break the database. I have changed everything I could think of, and can't figure out why this isn't working. Yes I understand the that injections could break our database, and we will work on updating the code soon to mysqli but we need this working now. I suspect my syntax isn't correct and the first line may need to be moved somewhere, but I am not the strongest in PHP and I am working with code that was written by previous interns. Thank you in advance.
Switch to mysqli_* functions is the right answer.
The answer if intend to stayg with the deprecated and dangerous mysql_* functions:
Here you set a new variable equal to your escaped $_POST[]:
$studentTalking = mysql_real_escape_string($_POST['studentTalking']);
But in your SQL you still refer to the $_POST array... Switch your SQL over to use your new variable you created
$sql = <<<SQL
UPDATE `tgtw_rsvp` SET
`studentName`='$studentName',
`studentEmail`='{$data['studentEmail']}',
`studentPhone`='{$data['studentPhone']}',
`studentID`='{$data['studentID']}',
`studentTalking`= '$studentTalking',
`resume` = '{$data['resume']}'
WHERE `id`={$data['date_time']} AND (`studentName` IS NULL OR `studentName`='')
SQL;
Because you are not using the stripped variable but still the raw POST data.
How do you escape ' on doctrine?
I made this code
$query = $em->createQuery(
"SELECT a FROM AcmeTopBundle:ArtData a WHERE
a.name = '". mysql_escape_string($name) ."'");
but when the $name is A'z
it returns error
[Doctrine\ORM\Query\QueryException]
SELECT a FROM AcmeTopBundle:ArtData a WHERE
a.name = 'A\'s'
I think I escaped by mysql_escape_string in case of using raw sql.
How can I avoid this error on doctrine?
The way I usually handle this is using parameters and querybuilder (https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/query-builder.html)...
$qb = $em->createQueryBuilder(
"SELECT a FROM AcmeTopBundle:ArtData a WHERE
a.name = :name")
->setParameter('name',$name);
$result = $qb->getQuery()->execute();
Well, even though there is accepted answer it is not for question as it is in title.
#Sven's answer comes close, but fails to mention:
Doctrine documentation
To escape user input in those scenarios use the Connection#quote() method.
And I have a gripe with "scenarios", or more with people pushing prepared statements like some holy grail. Well they are nice in theory, in practice at least in PHP they are quite shity, as they are unable to do simple stuff like IN (<list>) or multi inserts with VALUES (<bla bla>), (<more stuff>) which is a huge ass deal, as without it one ends up resorting to quite sub-optimal SQL (to put it lightly) quite commonly (well if one religiously insist on prepared statements at least).
This does not answer your question, but explains what's wrong with your code. It didn't fit into a comment.
You cannot and should not use mysql_escape_string()
It is the wrong escape function, the right one used to be mysql_real_escape_string(). Reading the documentation does not sound like it, but to properly escape, you have to know which character encoding is being used. In western encoding schemes like ASCII, ISO-8859-x or even UTF-8 it probably does not make a difference, but there are some exotic chinese encodings around which absolutely need to know whether that " byte belongs to another byte, or comes on it's own.
When using mysql_real_escape_string(), you need to have an already open DB connection created with mysql_connect(). If you don't, PHP tries to open a new connection with default user and password as defined in the php.ini file. This usually results in an error because without password the database won't let you do anything. And additionally, if you have success, then the encoding setting of this connection most likely is not the one used by Doctrine.
Using any of the mysql_* functions is wrong, because these are deprecated. The correct way would be to use mysqli_* functions.
Doctrine may use any of the three database connection methods: mysql, mysqli or PDO. You have to choose the one really being used if you want to manually call the correct escaping function. While the connection is already created. And somehow you need to grab that connection resource to allow the function you are calling to detect the used encoding.
So in the end there are plenty of reasons why it is wrong to just use any escaping that sound like it is doing the job.
The right way is to use the escaping of the database layer you are using. If you use Doctrine, the use it for escaping. Or better, avoid escaping, use prepared statements or the query builder and let Doctrine deal with the rest.
Based on https://stackoverflow.com/a/13377430/829533
you can use prepared statements http://docs.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/data-retrieval-and-manipulation.html#using-prepared-statements
From the documentation:
$date = new \DateTime("2011-03-05 14:00:21");
$stmt = $conn->prepare("SELECT * FROM articles WHERE publish_date > ?");
$stmt->bindValue(1, $date, "datetime");
$stmt->execute();
This will show how to insert the data into the database where you would normally have to use real_escape_string.
Doctrine and Symfony 3 using prepared not QueryBuilder:
// get the post value
$value = $request->request->get('value');
$sql = "INSERT INTO `table_name`
(`column_name1`,`column_name2`)
VALUES
('Static Data',?)
";
$em = $this->getDoctrine()->getManager();
$result = $em->getConnection()->prepare($sql);
$result->bindValue(1, $value);
$result->execute();
Now for a bonus to get a success/fail if you are using auto increment records:
$id = $em->getConnection()->lastInsertId();
if $id has a value then it executed the insert. If it does not the insert failed.
I have the following query
$query="DELETE FROM salesinvoiceitems WHERE invoiceNumber=".$this->put('invoiceNumber');
Here $this->put('invoiceNumber'); always have values like "M\34\SD". Due to slashes in values it doesn't work as expected.
I researched and found the mysql_escape_string can be used for this purpose but its deprecated now as per the manual. So whats my best bet here?
Why not use Codeingiter Active Record instead? An example:
$this->db->where('invoiceNumber', $this->put('invoiceNumber'));
$this->db->delete('salesinvoiceitems');
Taken from Codeigniter documentation:
Beyond simplicity, a major benefit to using the Active Record features
is that it allows you to create database independent applications,
since the query syntax is generated by each database adapter. It also
allows for safer queries, since the values are escaped automatically
by the system.
There's a method in the activerecord called escape, so you should :
$invoice = $this->db->escape($yourVar);
$query = "DELETE FROM salesinvoiceitems WHERE invoiceNumber=$invoice";
Which will protect against sql injection as it escapes the var.
Try this
$query="DELETE FROM salesinvoiceitems WHERE invoiceNumber=".addslashes($this->put('invoiceNumber'));
Try strip slashes
$query="DELETE FROM salesinvoiceitems WHERE invoiceNumber='".($this->put('invoiceNumber')). "'";
I have been trying to figure this out, but google wasn't turning up any real answers to my question.
I am using PHP (with CodeIgniter) and MySQL, is there a way that I can use bind variables with my SQL Statements?
Well, with CI you can:
$sql = "SELECT * FROM table WHERE name = ? AND email = ?";
$query = $this->db->query($sql, array($name,$email));
return $query->row_array();
This binds the $name and $email variable to th respective positions inside the query string. Is this what you mean?
There's also Active Record (a custom ORM, or sortof), which is pretty nice.
All of the above automatically escape values. You can also escape manually with $this->db->escape($string) and, for column names, with $this->db->protect_identifier($column_name). But it's all in the manual, have a read at it.
You can use PDOStatement::bindParam(), which may be significantly faster than CIs functions, depending on the use case.
I know that mysql_real_escape_string()
prepends backslashes to the following characters: \x00, \n, \r, \, ', " and \x1a
I know how this protects a query from injection into something like a variable in a where clause. But here's a scenario I am unsure of:
$query = "SELECT * FROM $db WHERE 1";
If $db is taken from a user input, then the user could insert something like:
$db = 'RealDatabase WHERE 1; DELETE FROM RealDatabase WHERE 1; SELECT FROM RealDatabase';
From my understanding, mysql_real_escape_string() would not affect this string,
making the final query:
$query = "SELECT * FROM RealDatabase WHERE 1; DELETE FROM RealDatabase WHERE 1; SELECT FROM RealDatabase WHERE 1";
which would delete the database. Is there another level of protection I am unaware of?
The level of protection you are looking for is supplied by backticks:
"SELECT * FROM `$db` WHERE 1";
Backticks are used to qualify identifiers that could otherwise be ambiguous (ie. MySQL reserved words), and if you are accepting user input or have variably-named columns or databases, you absolutely should use backticks, or I can promise that you will run into trouble in the future. For example, what if you had a system where a temporary field name was created with some user input, only it turned out the field ended up being named update?
"SELECT field1,field2,update FROM table;"
It fails miserably. However:
"SELECT `field`,`field2`,`update` FROM table"
works just fine. (This is actually a real example from a system I worked on a few years ago that had this problem).
This solves your problem in terms of putting in bad SQL. For instance, the following query will simply return an "unknown column" error, where test; DROP TABLE test is the injected attack code:
"SELECT * FROM `test; DROP TABLE test`;"
Be careful though: SQL Injection is still possible with backticks!
For instance, if your $db variable contained data that had a backtick in it, you could still inject some SQL in the normal way. If you're using variable data for database and field names, you should strip it of all backticks before putting it into your statement, and then qualifying it with backticks once inside.
$db = str_replace('`','',$db);
$sql = "SELECT * FROM `$db` WHERE 1";
I utilize a database wrapper which has separate functions for sanitizing data and sanitizing database identifiers, and this is what the latter does :)
You should really look into binding your SQL queries.
This will protect you from basically all SQL injection. It boils down to this:
(taken from PHP.net)
$stmt = mssql_init('NewUserRecord');
// Bind the field names
mssql_bind($stmt, '#username', 'Kalle', SQLVARCHAR, false, false, 60);
// Execute
mssql_execute($stmt);
And PHP has support for binded queries on basically all databases. Oh and of course you should still sanitize all input & output(display).
More info:
- http://php.net/manual/en/function.mssql-bind.php
No, mysql_real_escape_string isn't going to help you here. The function is not context-sensitive (it can't be, because it doesn't HAVE any context), and this is a completely different threat model.
You need to go and validate that the table exists, without sending the user-inputted table name directly to the server. The best solution is to use a server-side array/look-up table containing the table names they are allowed to use. If they try to use something that's not in there, then don't let them.
If you really need ALL of the tables, then you can just ask the server "what tables do you have?" and run through it's output (optionally caching it for some period of time to prevent asking the server every time) - but chances are, eventually you'll have a table that you don't want then to poke around in, and then you need to use the array thing anyway, so just go ahead and do that.
Instead of inserting the database name in the get query you can make a separate table of database names and ids. Then append only the id to the query. Then you can look up the corresponding database name for that id and use that. You can then make sure that the id received is numeric (is_numeric) and you can also be certain that the user can only choose from the databases that are in your list.
(Additionally this will prevent users from finding out names of databases and possibly use them elsewhere in an SQL injection on your site.)
Using the first method you parse the database name before using it in your query and make sure it contains no spaces.
Since table names do not accept whitespace characters, just strip them out. That would make the above $DB RealDatabaseWHERE1;DELETEFROMRealDatabase..... Such would invalidate the query, but prevent the flaw.
If you want to prevent this kind of 'hackish' things, just do explode(' ', $db) then get the result array's [0]. That would get the first part (RealDatabase) and nothing else.
Its just best to use it any time that you have questionable data being used. If you are specifying the table yourself and there's no room for tampering, there's no need to escape it. If your users are deciding anything that could potentially get run as a query, escape it.
If you really really must use a get from the user (bad bad bad) for your database then use the following style of coding...
$realname = '';
switch ($_GET['dbname']){
case 'sometoken' : $realname = 'real_name'; break;
case 'sometoken1' : $realname = 'real_name1'; break;
case 'sometoken2' : $realname = 'real_name2'; break;
case 'sometoken3' : $realname = 'real_name3'; break;
case 'sometoken4' : $realname = 'real_name4'; break;
case default : die ('Cheeky!!!');
}
$query = "SELECT * FROM `{$realname}` WHERE 1";
or alternatively ...
$realname = $tablenames[$_GET['dbname']];
if (!$realname)
die ('Cheeky!!!');
Using these 2 ways or some similar coding will protect your input from unexpected values.
It also means the user never gets to see the real table or database names which they may be able to infer information from.
Make sure you check the content of $_GET['dbname'] to make sure it's valid first otherwise warnings will be issued.
I still say this is a very bad design, it is reminiscent of allowing users to provide a filename and passing that through to I/O functions without a check. It simply too unsafe to consider.
Security is too important to let laziness rule.