This question already has answers here:
What are the best PHP input sanitizing functions? [duplicate]
(14 answers)
Closed 10 years ago.
I've used mysql_real_escape_string() to sanitise data when inserting it into the database, is it okay to use it again when retrieving data from the database?
It's not ok to use it at any time. The MySQL extension has been deprecated. Use PDO or MySQLi instead.
When using data in a query, use parameter binding instead of string manipulation for sanitising purposes.
You do not need to sanitise data on retrieval. If you're displaying the data in an HTML page, use the htmlspecialchars() or htmlentities() functions instead.
Update
To explain, you should not be storing data with escape characters in it. The best approach is to store data as received without modification (this is external to any validation you use to filter inputs prior to storing).
PDO and MySQLi both support parameter binding which is the safest way to store volatile data, eg (PDO)
$stmt = $pdo->prepare('INSERT INTO tableName VALUES (:param1, :param2)');
$stmt->bindParam('param1', $var1);
$stmt->bindParam('param2', $var2);
$stmt->execute();
Upon retrieval, you will receive the data as it went in so you do not need to modify it again.
To safely display this data in an HTML page, use one of the encoding functions listed above, eg
$stmt = $pdo->prepare('SELECT name FROM tableName');
$stmt->execute();
$row = $stmt->fetch(PDO::FETCH_ASSOC);
?>
<p>Hello, <?= htmlspecialchars($row['name']) ?></p>
No, mysql_real_escape_string() (and it's more modern version mysqli::real_escape_string()) should not be used on data retrieved from the database.
The only reason for escaping data for insertion into the database is because you are assembling it as string-data in another language: SQL. That is the purpose of escaping. If there was an API call where you provided all the elements as discrete parameters, you would not need to escape the data. But that's not how SQL works.
(Similarly, stripslashes() is only needed if you can't turn off magic quotes in your PHP instance.)
Yes always.
$username = stripslashes($_POST['username']);
$username = mysql_real_escape_string($_POST['username']);
$password = mysql_real_escape_string(md5($_POST['password']));//with md5
And retrieve----
$req = mysql_query('select password,id from users where username="'.$username.'"');
$dn = mysql_fetch_array($req);
if($dn['password']==md5($password) and mysql_num_rows($req)>0)
{ // ...
The reason you want to sanitize on retrieval is that most injections happen here. Case in point Facebook's hack from a user a year ago--he submitted a mysql_query retrieval into the browser to fetch another users data. And wound up inside the admin's program.
Related
I was reading lots of forums and answers on Stack over flow regarding SQL-Injection
and i came to know this is very basic level of SQL-injection
$_POST['name'] = 'xyz;DROP Table users';
mysqli_query ('select * from abc where name='."$_POST['name']")
To prevent this
Use mysqli_escape_stirng on any input that comes from user can save me from SQl-injection
Use PDO and prepare statement can also save me from SQL-injection
Q1. What i want to know here how passing data to Mysqli_escape_string can save me from SQL-Injection
$safe_variable = mysqli_escape_String($connection ,$_POST['name'];
How mysqli_escape_string will only save "XYZ" from POST data and leave the rest of the part (if that is the case)
Q2. How PDO will save me from SQL-Injection
$stmt = $dbh->prepare("select * from ABC where name = :name");
$stmt->bindParam(':name',$name);
$name = $_POST['name'];
$stmt->execute();
Any help in this regard his highly appreciated
The problem with incorporating user input into SQL is that in the resulting SQL you can’t tell which parts were provided by the developer and which by the user. That’s why the developer must ensure that user input gets interpreted as intended.
This is where string escaping functions and parameterization come in:
String escaping functions like mysqli_real_escape_string process the value so that it can be securely used in a string literal without fearing it may be interpreted as anything else than string data.
However, it is important to note that the value is actually placed in a string literal and nowhere else as it’s only intended for that specific purpose, i. e., it ensures that the passed data is interpreted as string data only when placed inside a string literal. Unfortunately, the PHP manual fails to mention the string literal part.
Parameterization as implemented by prepared statements separate the SQL and the data parameters. So there can’t be a confusion of SQL code and provided data. With server-side prepared statements first the statement gets prepared having only parameter placeholders and then the parameter values get passed for execution. And whenever a parameter is encountered, the DBMS uses the corresponding parameter value.
As for your specific example:
What i want to know here how passing data to Mysqli_escape_string can save me from SQL-Injection
$safe_variable = mysqli_escape_String($connection ,$_POST['name'];
How mysqli_escape_string will only save "XYZ" from POST data and leave the rest of the part (if that is the case)
It doesn’t because you didn’t put the value in a string literal. However, the following would work:
mysqli_query("select * from abc where name='$safe_variable'")
How PDO will save me from SQL-Injection
$stmt = $dbh->prepare("select * from ABC where name = :name");
$stmt->bindParam(':name',$name);
$name = $_POST['name'];
$stmt->execute();
As already said, you explicitly state what the SQL looks like by preparing the statement. And then you pass the parameters for execution. As the parameterized SQL and its parameters are separated, they won’t mix and a passed parameter value can’t be mistaken as SQL.
Q1:
mysql(i)_real_escape_string() calls MySQL's library function
mysql(i)_real_escape_string, which prepends backslashes to the following
characters: \x00, \n, \r, \, ', " and \x1a.
(http://php.net/mysqli_real_escape_string)
Note that this depends on the character encoding (not workin in this case is SET NAMES ... (security risk!!!), $mysqli->set_charset('utf8'); should be used!). (You can read about encoding in my post Mastering UTF-8 encoding in PHP and MySQL.)
How does it prevent SQL injection?
- Well it prevents breaking the variables context by escaping ' etc, the thing is, that mysql_query and mysqli_query only execute one query per query, that means, it simply ignores ;DROP Table users.
mysqli_real_escape_string DOES NOT prevent inserting code like DROP DATABASE.
Only PDO and/or mysqli_multi_query are vulnerable in this case.
Q2:
The statement is sent to the server first, then the bound variables will get sent seperated and then the statement gets executed, in this case, the security is provided by the database library, not by the client library. You should prefere this.
That means, you first send $dbh->prepare("select * from ABC where name = :name"); to the server and the database knows your bind param will be inserted into the :name placeholder and it will automatically wrap it properly to not break out of its supposed context. The database will try to look for a name value of xyz;DROP Table users and it won't executed any command, just fill that variable space.
I think this is the case for most SQL escaping functions:
They escape the control chars like ;, ', ", ...
So your string
xyz;DROP Table users
Will be escaped by the functions to
xyz\;DROP Table users
So your string now isn't a valid SQL command anymore.
But be aware of HTML tags in the data stored in a DB.
If I insert for example
<script>alert('foobar');</script>
This will be stored in DB and not treated by the SQL escape functions. If you print out the field somewhere again, the JS will be executed by the visitors browser.
So use in addtion htmlspecialchars() or htmlentities() for sanitize user input. This is also true for prepared statements.
This question already has answers here:
How can I prevent SQL injection in PHP?
(27 answers)
Closed 2 years ago.
Which means, at the moment, are the safest for screening data in php to send them to the mysql database.
Thank, you )
I believe mysql_real_escape_string() mysqli_real_escape_string() is the best way to escape input data
Later edit since everything is deprecated now and information must be valid:
Try to use PDO as prepared statements are much safer or mysqli_*() functions if you really need to keep old code somewhat up-to-date.
Currently the most preferred way to insure your safety is prepared statements.
example:
$preparedStatement = $db->prepare('SELECT * FROM memebers WHERE username = :username');
$preparedStatement->execute(array(':username' => $username));
$rows = $preparedStatement->fetchAll();
then when displaying your data use htmlspecialchars()
validMySQL($var) {
$var=stripslashes($var);
$var=htmlentities($var);
$var=strip_tags($var);
$var=mysql_real_escape_string($var);
return $var
}
The above code helps to sanitize most invalid data, just remember that you've to be connected to mysql database for mysql_real_escape_string to work...
I saw several examples and people using this way to query the database in a login form.
I'm not fully sure is this is the best way to do a login form secure.
This is the query in PHP:
$query = "SELECT * FROM users WHERE usern = '".$_POST['username']."' AND passw = '".md5($_POST['password'])."'";
Is enough having md5() on the password post to avoid sql injection?.
I think that the md5 function will convert all characters and sql strings to a 32 char string.
Which other ways can I protect the login form?
mysql_real_escape_string($_POST['username']), etc.
Although it's better to use the mysqli extension and use prepared statements.
(Assuming you're using MySQL)
Edit: In response to the comment below, it might be good to use this for LIKE queries:
addcslashes(mysql_real_escape_string($_POST['username']), '%_')
You must sanitize your data before you let it near your database. The simplest way to do this is by using mysql_real_escape_string($_POST['username']) but this is only the very least you need to do.
If you're using a framework like CodeIgniter, you can use their in-build functionality which strips $_POST or $_GET inputs of any XSS risk. Otherwise, I'd recommend these posts:
What's the best method for sanitizing user input with PHP?
Clean & Safe string in PHP
You need to escape $_POST['username'] as well
and yes md5 will protect you from sql injection.
For this example, something like this would be ok
$query = "SELECT * FROM users WHERE MD5(usern) = '".md5($_POST['username'])."' AND passw = '".md5($_POST['password'])."'";
The way you have build your query easily allows to inject pieces of code in the username. You can use prepared statements to avoid that:
http://php.net/manual/en/pdo.prepared-statements.php
Prepared statements basically will describe how the statement will be structured, and adds the data afterwards. This way, the user can not alter the structure of the statement with the input data.
If you make a function which sanitizes all POSTS and GETS you are safe
function clean() {
foreach($_POST as $key => $val) {
$_POST[$key] = mysql_real_escape_string($val);
}
}
You can also use PDO and statements with variables, and PDO will clean automatically.
<?php
try {
$dbh = new PDO("mysql:host=$hostname;dbname=$db", $dbusername, $dbpassword);
$query = "SELECT * FROM users WHERE usern = ? AND passw = ?";
$sth=$dbh->prepare($sql);
$sth->execute(array($_POST['username'], md5($_POST['password']));
$result = $sth->fetch();
}
} catch(PDOException $e) {
echo $e->getMessage();
exit;
}
PDO is the Best way to stop SQL Injection in PHP
Just one simple solution use parameters for fields like username and password so that SQL command string is separably sent from the parameters and then attacker will only get blank responses.When parameters are used SQL command string is parsed and compiled separately from the parameters. Using prepared statements is the best solution.
I need to use a get function to retrieve $title variable from a url.
$title=$_GET["title"];
The $title is later used in a MySQL query.
The question is how to make this secure?
In other words, how to neutralize any malicious codes sent through the URL.
(For a value of "secure" equal to "to prevent it breaking the database"): use any database API that uses bound parameters.
Bound parmeters tend to let the database handle the escaping (so uses escaping routines written by the database authors rather then the language authors) and uses a syntax that is less prone to being forgotten about for that one vital escape then manually escaping each piece of input data with (for example) mysql_real_escape_string.
You might need to take other steps later before you do something with the data in a different context (e.g. to make it safe to insert into an HTML document)
You must use mysql_real_escape_string() to escape all characters that could interfere with you database. If you're displaying this title, you should also make use of htmlentities() or striptags()
As of PHP 5.2, you can use filter_input() and filter_input_array() to sanitize and validate the the $_GET or $_POST data.
For example:
$my_string = filter_input(INPUT_GET, 'my_string', FILTER_SANITIZE_STRING);
Read more about that in this article here.
For SQL queries, it's very recommended that you use PDO with prepared statements to protect from SQL injections. You can read about PDO in the PHP Manual here.
You can use mysql_real_escape_string function (Escapes special characters in a string for use in an SQL statement)
Php Manuel
Use query parameters. There is a number of different ways to connect to mysql from PHP, and they way to use parameters varies a little from framework to framework. Here is an example using PDO:
$dbh = new PDO('mysql:dbname=test;host=127.0.0.1', 'username', 'password');
$sth = $dbh->prepare("select * from table where title = :title")
$sth->execute(array(':title' => $_GET["title"]));
$rows = $sth->fetchAll();
var_dump($rows);
When a user goes to my site, my script checks for 2 cookies which store the user id + part of the password, to automatically log them in.
It's possible to edit the contents of cookies via a cookie editor, so I guess it's possible to add some malicious content to a written cookie?
Should I add mysql_real_escape_string (or something else) to all my cookie calls or is there some kind of built in procedure that will not allow this to happen?
What you really need to do is not send these cookie values that are hackable in the first place. Instead, why not hash the username and password and a (secret) salt and set that as the cookie value? i.e.:
define('COOKIE_SALT', 'secretblahblahlkdsfklj');
$cookie_value = sha1($username.$password.COOKIE_SALT);
Then you know the cookie value is always going to be a 40-character hexidecimal string, and can compare the value the user sends back with whatever's in the database to decide whether they're valid or not:
if ($user_cookie_value == sha1($username_from_db.$password_drom_db.COOKIE_SALT)) {
# valid
} else {
#not valid
}
mysql_real_escape_string makes an additional hit to the database, BTW (a lot of people don't realize it requires a DB connection and queries MySQL).
The best way to do what you want if you can't change your app and insist on using hackable cookie values is to use prepared statements with bound parameters.
The point of mysql_real_escape_string isn't to protect against injection attacks, it's to ensure your data is accurately stored in the database. Thus, it should be called on ANY string going into the database, regardless of its source.
You should, however, also be using parameterized queries (via mysqli or PDO) to protect yourself from SQL injection. Otherwise you risk ending up like little Bobby Tables' school.
I only use mysql_real_escape_string before inserting variables into an SQL statement. You'll just get yourself confused if some of your variables are already escaped, and then you escape them again. It's a classic bug you see in newbies' blog webapps:
When someone writes an apostrophe it keeps on adding slashes ruining the blog\\\\\\\'s pages.
The value of a variable isn't dangerous by itself: it's only when you put it into a string or something similar that you start straying into dangerous waters.
Of course though, never trust anything that comes from the client-side.
Prepared statements and parameter binding is always a good way to go.
PEAR::MDB2 supports prepared statements, for example:
$db = MDB2::factory( $dsn );
$types = array( 'integer', 'text' );
$sth = $db->prepare( "INSERT INTO table (ID,Text) (?,?)", $types );
if( PEAR::isError( $sth ) ) die( $sth->getMessage() );
$data = array( 5, 'some text' );
$result = $sth->execute( $data );
$sth->free();
if( PEAR::isError( $result ) ) die( $result->getMessage() );
This will only allow proper data and pre-set amount of variables to get into database.
You of course should validate data before getting this far, but preparing statements is the final validation that should be done.
You should mysql_real_escape_string anything that could be potentially harmful. Never trust any type of input that can be altered by the user.
I agree with you. It is possible to modify the cookies and send in malicious data.
I believe that it is good practice to filter the values you get from the cookies before you use them. As a rule of thumb I do filter any other input that may be tampered with.
Yegor, you can store the hash when a user account is created/updated, then whenever a login is initiated, you hash the data posted to the server and compare against what was stored in the database for that one username.
(Off the top of my head in loose php - treat as pseudo code):
$usernameFromPostDbsafe = LimitToAlphaNumUnderscore($usernameFromPost);
$result = Query("SELECT hash FROM userTable WHERE username='$usernameFromPostDbsafe' LIMIT 1;");
$hashFromDb = $result['hash'];
if( (sha1($usernameFromPost.$passwordFromPost.SALT)) == $hashFromDb ){
//Auth Success
}else{
//Auth Failure
}
After a successful authentication, you could store the hash in $_SESSION or in a database table of cached authenticated username/hashes. Then send the hash back to the browser (in a cookie for instance) so subsequent page loads send the hash back to the server to be compared against the hash held in your chosen session storage.
mysql_real_escape_string is so passé... These days you should really use parameter binding instead.
I'll elaborate by mentionning that i was referring to prepared statements and provide a link to an article that demonstrates that sometimes mysl_real_escape_string isn't sufficient enough: http://www.webappsec.org/projects/articles/091007.txt
I would recommend using htmlentities($input, ENT_QUOTES) instead of mysql_real_escape_string as this will also prevent any accidental outputting of actual HTML code. Of course, you could use mysql_real_escape_string and htmlentities, but why would you?