The code below is written in php:
$user = addslashes($_POST['user']);
$pwd = addslashes($_POST['pwd']);
$query = "SELECT * FROM userdata WHERE UserName='$user' AND Password=PASSWORD('$pwd')";
the query will then be sent to mysql
Is there anything more I need to take care of?
Please point out.
No it's not safe, use mysql_real_escape_string at minimum:
$user = mysql_real_escape_string($_POST['user']);
$pwd = mysql_real_escape_string($_POST['pwd']);
And for better security go for prepared statements.
Best Options:
PDO
mysqli
You may ask which one to choose, check out:
What is difference between mysql,mysqli and pdo?
Nope.
The reason is that while a single quote ' is not the only char that break a sql query, quotes are the only chars escaped by addslashes().
Better: use mysql_real_escape_string
$user = mysql_real_escape_string($_POST['user'], $conn);
$pwd = mysql_real_escape_string($_POST['pwd'], $conn);
$query = "SELECT * FROM userdata WHERE UserName='$user' AND Password=PASSWORD('$pwd')";
Best: use PDO and prepared statements
$stmt = $dbh->prepare("SELECT * FROM userdata WHERE UserName=':user' AND Password=PASSWORD(':pass')");
$stmt->bindParam(':user', $user);
$stmt->bindParam(':pass', $pass);
No. You should not be using addslashes() to escape your data. That's been obsolete for years. You should be either:
using mysql_real_escape_string() as a replacement
using prepared statements with PDO or MySQLi
Plus using MySQL's Password() function is also poor pracdtive. Use hashes with salts. Bcrypt is my recommendation. Also, check out PHPass.
Protecting against SQL injection is easy:
Filter your data.
This cannot be overstressed. With good data filtering in place, most security concerns are mitigated, and some are practically eliminated.
Quote your data.
If your database allows it (MySQL does), put single quotes around all values in your SQL statements, regardless of the data type.
Escape your data.
Sometimes valid data can unintentionally interfere with the format of the SQL statement itself. Use mysql_escape_string() or an escaping function native to your particular database. If there isn't a specific one, addslashes() is a good last resort.
Read more: http://phpsec.org/projects/guide/3.html#3.2
Related
Any way to prevent malicious sql statements without using prepared statements and parameterized queries?
Example after simplify:
<?php
$con = mysqli_connect($_POST['db_server'], $_POST['db_user'],
$_POST['db_password'], $_POST['db_database']) or die(mysql_error());
$result = mysqli_query($con, $_POST['query_message']);
?>
Is it possible to check out the parameter $_POST['query_message'] is safe or not?
You should always build your queries within your code and then sanitise any variables you're going to use within them. NEVER pass the query or the database connection variables in via $_POST unless your user is querying the database via that form, in which case I'd recommend you just install phpMyAdmin.
As for sanitising your variables, if you really don't want to use PDO's prepared statements, you can sanitise incoming integers as follows:
$id = (isset($_POST['id']) ? (int)$_POST['id'] : null);
if ($id) {
$sql = "SELECT *
FROM `table`
WHERE `id` = {$id}";
}
And for strings use this:
$username = (isset($_POST['username']) ? mysqli_real_escape_string($con, $_POST['username']) : null);
if ($username) {
$sql = "SELECT *
FROM `table`
WHERE `username` = {$username}";
}
You can also call real_escape_string() directly on your $con object as follows:
$username = (isset($_POST['username']) ? $con->real_escape_string($con, $_POST['username']) : null);
However, as with #Shankar-Damodaran above, I highly suggest you do use PDO prepared statements to query your database.
Why you don't wanna use Prepared Statements ? That is really weird. I strongly suggest you should go for it.
You could make use of mysqli::real_escape_string for escaping quotes that is commonly used for SQL Injection Attacks.
Something like...
OOP Style
$message = $mysqli->real_escape_string($_POST['query_message']);
Procedural Style
$message = mysqli_real_escape_string($link,$_POST['query_message']);
other way is using:
htmlentities($query);
as an extra you could use preg_match() regular expressions to avoid
the inclusion of certain words (SELECT, DROP, UNION .......)
Example:
try{
$query = sprintf("SELECT * FROM users WHERE id=%d", mysqli_real_escape_string($id));
$query = htmlentities($query);
mysqli_query($query);
}catch(Exception $e){
echo('Sorry, this is an exceptional case');
}
There are real world cases where prepared statements are not an option.
For a simple example, a web page page where you can do a search on any number of any columns in the database table. SAy that table has 20 searchable columns. you would need a huge case statement that has all 20 single column queries, all 19+18+17+16+15+14+13+... 2 column queries, all possible 3 column queries... that's a LOT of code. much less to dynamically construct the where clause. That's what the OP means by prepared statements being less flexible.
Simply put, there is no generic case. If there was, php would have it already.
real_escape_string can be beaten. a common trick is to % code the character you are trying to escape so real_escape_string doesn't see it. then it gets passed to mysql, and decoded there. So additional sanitizing is still required. and when all characters used in injection are valid data, it's a PITA, because you can't trust real_escape_string to do it.
If you are expecting an integer, it's super easy.
$sanitized=(int)$unsanitized;
done.
If you are expecting a small text string, simply truncating the string will do the trick. does't matter that it's not sanitized if there's not enough room to hold your exploit
But there is no one size fits all generic function that can sanitize arbitrary data against sql injection yet. If you write one, expect it to get put into php. :)
Ok I would like to know how you convert this mysql code into mysqli.
function protect($string) {
return mysql_real_escape_string(strip_tags(addslashes($string)));
}
I know you change mysql to mysqli but it asks for 2 parameters this worked with mysql so I would like to see it in mysqli
also I haven't yet found someone on stackoverflow with a question about the new mysqli version so I wasn't able to find out myself
It is better not to use it at all!
mysql_real_escape_string() was a hack which was used to prevent SQL injection, and it didn't even do that 100%. This function was never meant to protect anything. It is a simple string formatting function.
mysqli_real_escape_string() is yet another hack to make the transition easier. Although, at the time of writing this post mysql_* has been deprecated for so long, that no one should have any excuse to use some kind of shim for transitioning, because everyone should already be using MySQLi with prepared statements or even better PDO.
As for strip_tags() and addslashes() they are useless in this context and only mutilate your data. Don't use them.
To protect against SQL injection, one should use prepared statements and ensure that no variable input is inserted into SQL directly.
For example:
$stmt = $mysqli->prepare('SELECT columnA FROM tableB WHERE columnC=?');
$stmt->bind_param('s', $someVariable);
$stmt->execute();
$result = $stmt->get_result();
This function is a bad idea.
Using strip_tags() and addslashes() indiscriminately on all incoming data needlessly mutilates it, with zero added security.
To feed data into the database, use only the string escaping function, real_escape_string().
To display data from the user on a HTML page, strip the tags then or use htmlspecialchars() to avoid any scripting attacks.
Try like this:
$mysqli = new mysqli("host", "username", "pword", "db");
function protect($string) {
return $mysqli->real_escape_string(strip_tags(addslashes($string)));
}
EDIT
$link = mysqli_connect("localhost", "root", "", "aaa");
$city = "'s Hertogenbosch";
$city = mysqli_real_escape_string($link, $city);
echo($city);
How do you add a single quote to a variable within a SQL statement? If I put 'jeremy' in place of the '\$user'\ variable it works perfectly. I can't figure out how to escape the quote for the variable in the SQL statement. Thank you for your help.
$resultArticles = mysql_query("SELECT COUNT(id) FROM articleList WHERE user = '\$user'\ ");
$totalArticlesLeaderboard = mysql_result($resultArticles, 0);
echo "<strong>Total Articles: </strong>" . $totalArticlesLeaderboard;
I've tried to find a suitable duplicate of your question, but I only found real dupes which are based on the ancient mysql_* functions. The mysql_* functions (like the ones you are using) are no longer maintained by the PHP commuity (for some time now) and the deprecation process has begun on it. See the red box?
You should really try to pick up the better PDO or MySQLi. Both of these option should be fine. Imho PDO has a better API, but mysqli is more towards mysql (in most cases PDO will do whatever you want to use it for).
With the two "new" API there is also the possibilty to use prepared statements. With prepared statements you should not have to worry about manually escaping values before inserting them into your queries.
An example of this using the PDO API would be:
$db = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$stmt = $db->prepare('SELECT COUNT(id) FROM articleList WHERE user = :user');
$stmt->execute(array('user' => $user));
As you can see the values are not inserted directly into the query, but instead it uses placeholders. This code will make it impossible for people to inject arbitrary SQL into your query. And also you don't need to do any escaping anymore.
If you need more help in deciding between PDO or mysql check out the docs with more information about it. If you choose PDO you can find a good tutorial on the topic here.
Test this
$resultArticles = sprintf("SELECT COUNT(id) FROM articleList WHERE user='%s",
mysql_real_escape_string($user));
You should be able to just remove the escape characters:
$user = mysql_real_escape_string($user);
$resultArticles = mysql_query("SELECT COUNT(id) FROM articleList WHERE user = '$user'");
If you ever have trouble with variables, you can always just end the string and concatenate. I do this often to avoid confusion:
$user = mysql_real_escape_string($user);
$resultArticles = mysql_query("SELECT COUNT(id) FROM articleList WHERE user = '".$user."'");
As PeeHaa said, make sure you try to use PDO or MySQLi.
Don't forget to escape all user input, or they potentially can destroy your database. If you are using MySQLi, you can use mysqli::real_escape_string. Sanitizing ALL your user data is absolutely essential. DO NOT SKIP THIS!
If the variable $user contains any special characters, it is necessary to escape these, as shown in the first answer. If you don't have the mysql_real_escape_string() function available, use addslashes().
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.
<?php
$id = intval($_GET['id']);
$sql = mysql_query("SELECT username FROM users WHERE id = $id");
$row = mysql_fetch_assoc($sql);
$user = htmlspecialchars($row['username']);
?>
<h1>User:<?php echo $user ?></h1>
Can you see any threats in the above code? Do I have to use htmlspecialchars on everything I output? And should i use is_numeric or intval to check so that the get is numeric?
I'm just building a minimal site. I'm just wondering if the above code is vulnerable to sql injection, xss?
Generally speaking mysql_real_escape_string() is preferred but since it's a number, intval() is OK. So yes, it looks OK from a security perspective.
One thing though, on many platforms, ints are limited to 32 bits so if you want to deal in numbers larger than ~2.1 billion then it won't work. Well, it won't work how you expect anyway.
These sorts of security precautions apply to any form of user input including cookies (something many people forget).
I would strongly recommend using PDO and prepared statements. While your statement above looks safe, you're going to have problems as soon as you do more complex queries.
Instead of puzzling over whether a particular query is safe, learn about prepared statements and you won't have to worry. Here is your example, re-written with PDO:
# Make a database connection
$db = new PDO('mysql:dbname=your_db;host=your_db_server', 'username',
'password');
# The placeholder (:id) will be replaced with the actual value
$sql = 'SELECT username FROM users WHERE id=:id';
# Prepare the statement
$stmt = $db->prepare($sql);
# Now replace the placeholder (:id) with the actual value. This
# is called "binding" the value. Note that you don't have to
# convert it or escape it when you do it this way.
$stmt->bindValue(':id', $id);
# Run the query
$stmt->execute();
# Get the results
$row = $stmt->fetch();
# Clean up
$stmt->closeCursor();
# Do your stuff
$user = htmlspecialchars($row['username']);
I've added a lot of comments; it's not as much code as it looks like. When you use bindValue, you never have to worry about SQL injection.
Well,
You are casting the received id to an int ; so no possible SQL injection here.
And the rest of the DB query is "hard-coded", so no problem there either.
If id was a string in DB, you'd have to use mysql_real_escape_string, but for an integer, intval is the right tool :-)
About the output, you are escaping data too (and, as you are outputting HTML, htmlspecialchars is OK) ; so no HTML/JS injection.
So, this short portion of code looks OK to me :-)
As a sidenote, if you are starting developping a new website, it is the moment or never to take a look at either mysqli (instead of mysql), and/or PDO ;-)
It would allow you to use functionnalities provided by recent versions of MySQL, like prepared statements, for instance -- which are a good way to protect yourself from SQL injection !